2019-09-30 08:06:01 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-08-29 03:56:52 -04:00
|
|
|
require 'spec_helper'
|
2017-03-23 04:43:34 -04:00
|
|
|
|
2020-06-24 05:08:32 -04:00
|
|
|
RSpec.describe AvatarsHelper do
|
2018-04-25 11:32:47 -04:00
|
|
|
include UploadHelpers
|
2017-06-02 03:42:18 -04:00
|
|
|
|
2021-03-03 01:11:13 -05:00
|
|
|
let_it_be(:user) { create(:user) }
|
2017-03-23 04:43:34 -04:00
|
|
|
|
2018-08-09 09:47:47 -04:00
|
|
|
describe '#project_icon & #group_icon' do
|
|
|
|
shared_examples 'resource with a default avatar' do |source_type|
|
|
|
|
it 'returns a default avatar div' do
|
|
|
|
expect(public_send("#{source_type}_icon", *helper_args))
|
2021-04-28 14:10:12 -04:00
|
|
|
.to match(%r{<span class="identicon bg\d+">F</span>})
|
2018-08-09 09:47:47 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples 'resource with a custom avatar' do |source_type|
|
|
|
|
it 'returns a custom avatar image' do
|
|
|
|
expect(public_send("#{source_type}_icon", *helper_args))
|
2019-06-25 13:54:42 -04:00
|
|
|
.to eq "<img src=\"#{resource.avatar.url}\" />"
|
2018-08-09 09:47:47 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-01-30 01:08:49 -05:00
|
|
|
shared_examples 'Gitaly exception handling' do
|
|
|
|
before do
|
|
|
|
allow(resource).to receive(:avatar_url).and_raise(error_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'handles Gitaly exception gracefully' do
|
|
|
|
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
|
|
|
|
an_instance_of(error_class), source_type: 'Project', source_id: resource.id
|
|
|
|
)
|
|
|
|
expect { project_icon(resource) }.not_to raise_error
|
2018-08-09 09:47:47 -04:00
|
|
|
end
|
|
|
|
|
2020-01-30 01:08:49 -05:00
|
|
|
it_behaves_like 'resource with a default avatar', 'project'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when providing a project' do
|
|
|
|
let(:helper_args) { [resource] }
|
|
|
|
let(:resource) { create(:project, name: 'foo') }
|
|
|
|
|
|
|
|
it_behaves_like 'resource with a default avatar', 'project'
|
|
|
|
|
2018-08-09 09:47:47 -04:00
|
|
|
it_behaves_like 'resource with a custom avatar', 'project' do
|
|
|
|
let(:resource) { create(:project, :public, avatar: File.open(uploaded_image_temp_path)) }
|
2020-01-30 01:08:49 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when Gitaly is unavailable' do
|
|
|
|
let(:error_class) { GRPC::Unavailable }
|
|
|
|
|
|
|
|
include_examples 'Gitaly exception handling'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when Gitaly request is taking too long' do
|
|
|
|
let(:error_class) { GRPC::DeadlineExceeded }
|
|
|
|
|
|
|
|
include_examples 'Gitaly exception handling'
|
2018-08-09 09:47:47 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when providing a group' do
|
|
|
|
it_behaves_like 'resource with a default avatar', 'group' do
|
|
|
|
let(:resource) { create(:group, name: 'foo') }
|
|
|
|
let(:helper_args) { [resource] }
|
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'resource with a custom avatar', 'group' do
|
|
|
|
let(:resource) { create(:group, avatar: File.open(uploaded_image_temp_path)) }
|
|
|
|
let(:helper_args) { [resource] }
|
|
|
|
end
|
|
|
|
end
|
2018-04-25 11:32:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
describe '#avatar_icon_for' do
|
|
|
|
let!(:user) { create(:user, avatar: File.open(uploaded_image_temp_path), email: 'bar@example.com') }
|
|
|
|
let(:email) { 'foo@example.com' }
|
|
|
|
let!(:another_user) { create(:user, avatar: File.open(uploaded_image_temp_path), email: email) }
|
|
|
|
|
|
|
|
it 'prefers the user to retrieve the avatar_url' do
|
|
|
|
expect(helper.avatar_icon_for(user, email).to_s)
|
|
|
|
.to eq(user.avatar.url)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'falls back to email lookup if no user given' do
|
|
|
|
expect(helper.avatar_icon_for(nil, email).to_s)
|
|
|
|
.to eq(another_user.avatar.url)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-03-03 01:11:13 -05:00
|
|
|
describe '#avatar_icon_for_email', :clean_gitlab_redis_cache do
|
2018-04-25 11:32:47 -04:00
|
|
|
let(:user) { create(:user, avatar: File.open(uploaded_image_temp_path)) }
|
|
|
|
|
2021-03-03 01:11:13 -05:00
|
|
|
subject { helper.avatar_icon_for_email(user.email).to_s }
|
|
|
|
|
|
|
|
shared_examples "returns avatar for email" do
|
|
|
|
context 'using an email' do
|
|
|
|
context 'when there is a matching user' do
|
|
|
|
it 'returns a relative URL for the avatar' do
|
|
|
|
expect(subject).to eq(user.avatar.url)
|
|
|
|
end
|
2018-04-25 11:32:47 -04:00
|
|
|
end
|
|
|
|
|
2021-03-03 01:11:13 -05:00
|
|
|
context 'when no user exists for the email' do
|
|
|
|
it 'calls gravatar_icon' do
|
|
|
|
expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20, 2)
|
2018-04-25 11:32:47 -04:00
|
|
|
|
2021-03-03 01:11:13 -05:00
|
|
|
helper.avatar_icon_for_email('foo@example.com', 20, 2)
|
|
|
|
end
|
2018-04-25 11:32:47 -04:00
|
|
|
end
|
|
|
|
|
2021-03-03 01:11:13 -05:00
|
|
|
context 'without an email passed' do
|
|
|
|
it 'calls gravatar_icon' do
|
|
|
|
expect(helper).to receive(:gravatar_icon).with(nil, 20, 2)
|
|
|
|
expect(User).not_to receive(:find_by_any_email)
|
2018-04-25 11:32:47 -04:00
|
|
|
|
2021-03-03 01:11:13 -05:00
|
|
|
helper.avatar_icon_for_email(nil, 20, 2)
|
|
|
|
end
|
2018-04-25 11:32:47 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2021-03-03 01:11:13 -05:00
|
|
|
|
2021-04-07 14:09:45 -04:00
|
|
|
it_behaves_like "returns avatar for email"
|
2021-03-03 01:11:13 -05:00
|
|
|
|
2021-04-07 14:09:45 -04:00
|
|
|
it "caches the request" do
|
|
|
|
expect(User).to receive(:find_by_any_email).once.and_call_original
|
2021-03-03 01:11:13 -05:00
|
|
|
|
2021-04-07 14:09:45 -04:00
|
|
|
expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url)
|
|
|
|
expect(helper.avatar_icon_for_email(user.email).to_s).to eq(user.avatar.url)
|
2021-03-03 01:11:13 -05:00
|
|
|
end
|
2018-04-25 11:32:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
describe '#avatar_icon_for_user' do
|
|
|
|
let(:user) { create(:user, avatar: File.open(uploaded_image_temp_path)) }
|
|
|
|
|
|
|
|
context 'with a user object passed' do
|
|
|
|
it 'returns a relative URL for the avatar' do
|
|
|
|
expect(helper.avatar_icon_for_user(user).to_s)
|
|
|
|
.to eq(user.avatar.url)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'without a user object passed' do
|
|
|
|
it 'calls gravatar_icon' do
|
|
|
|
expect(helper).to receive(:gravatar_icon).with(nil, 20, 2)
|
|
|
|
|
|
|
|
helper.avatar_icon_for_user(nil, 20, 2)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#gravatar_icon' do
|
|
|
|
let(:user_email) { 'user@email.com' }
|
|
|
|
|
|
|
|
context 'with Gravatar disabled' do
|
|
|
|
before do
|
|
|
|
stub_application_setting(gravatar_enabled?: false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a generic avatar' do
|
|
|
|
expect(helper.gravatar_icon(user_email)).to match_asset_path('no_avatar.png')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with Gravatar enabled' do
|
|
|
|
before do
|
|
|
|
stub_application_setting(gravatar_enabled?: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a generic avatar when email is blank' do
|
|
|
|
expect(helper.gravatar_icon('')).to match_asset_path('no_avatar.png')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a valid Gravatar URL' do
|
|
|
|
stub_config_setting(https: false)
|
|
|
|
|
|
|
|
expect(helper.gravatar_icon(user_email))
|
|
|
|
.to match('https://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'uses HTTPs when configured' do
|
|
|
|
stub_config_setting(https: true)
|
|
|
|
|
|
|
|
expect(helper.gravatar_icon(user_email))
|
|
|
|
.to match('https://secure.gravatar.com')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns custom gravatar path when gravatar_url is set' do
|
|
|
|
stub_gravatar_setting(plain_url: 'http://example.local/?s=%{size}&hash=%{hash}')
|
|
|
|
|
|
|
|
expect(gravatar_icon(user_email, 20))
|
|
|
|
.to eq('http://example.local/?s=40&hash=b58c6f14d292556214bd64909bcdb118')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'accepts a custom size argument' do
|
|
|
|
expect(helper.gravatar_icon(user_email, 64)).to include '?s=128'
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'defaults size to 40@2x when given an invalid size' do
|
|
|
|
expect(helper.gravatar_icon(user_email, nil)).to include '?s=80'
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'accepts a scaling factor' do
|
|
|
|
expect(helper.gravatar_icon(user_email, 40, 3)).to include '?s=120'
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'ignores case and surrounding whitespace' do
|
|
|
|
normal = helper.gravatar_icon('foo@example.com')
|
|
|
|
upcase = helper.gravatar_icon(' FOO@EXAMPLE.COM ')
|
|
|
|
|
|
|
|
expect(normal).to eq upcase
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-03-23 04:43:34 -04:00
|
|
|
describe '#user_avatar' do
|
|
|
|
subject { helper.user_avatar(user: user) }
|
|
|
|
|
|
|
|
it "links to the user's profile" do
|
|
|
|
is_expected.to include("href=\"#{user_path(user)}\"")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "has the user's name as title" do
|
|
|
|
is_expected.to include("title=\"#{user.name}\"")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "contains the user's avatar image" do
|
2017-05-10 00:26:17 -04:00
|
|
|
is_expected.to include(CGI.escapeHTML(user.avatar_url(size: 16)))
|
2017-03-23 04:43:34 -04:00
|
|
|
end
|
|
|
|
end
|
2017-06-02 03:42:18 -04:00
|
|
|
|
|
|
|
describe '#user_avatar_without_link' do
|
|
|
|
let(:options) { { user: user } }
|
2019-12-17 13:07:48 -05:00
|
|
|
|
2017-06-02 03:42:18 -04:00
|
|
|
subject { helper.user_avatar_without_link(options) }
|
|
|
|
|
|
|
|
it 'displays user avatar' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-06-02 03:42:18 -04:00
|
|
|
alt: "#{user.name}'s avatar",
|
2018-02-09 07:07:19 -05:00
|
|
|
src: avatar_icon_for_user(user, 16),
|
2017-09-25 04:13:15 -04:00
|
|
|
data: { container: 'body' },
|
|
|
|
class: 'avatar s16 has-tooltip',
|
|
|
|
title: user.name
|
2017-06-02 03:42:18 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with css_class parameter' do
|
|
|
|
let(:options) { { user: user, css_class: '.cat-pics' } }
|
|
|
|
|
|
|
|
it 'uses provided css_class' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-06-02 03:42:18 -04:00
|
|
|
alt: "#{user.name}'s avatar",
|
2018-02-09 07:07:19 -05:00
|
|
|
src: avatar_icon_for_user(user, 16),
|
2017-09-25 04:13:15 -04:00
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s16 #{options[:css_class]} has-tooltip",
|
|
|
|
title: user.name
|
2017-06-02 03:42:18 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with size parameter' do
|
|
|
|
let(:options) { { user: user, size: 99 } }
|
|
|
|
|
|
|
|
it 'uses provided size' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-06-02 03:42:18 -04:00
|
|
|
alt: "#{user.name}'s avatar",
|
2018-02-09 07:07:19 -05:00
|
|
|
src: avatar_icon_for_user(user, options[:size]),
|
2017-09-25 04:13:15 -04:00
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s#{options[:size]} has-tooltip",
|
|
|
|
title: user.name
|
2017-06-02 03:42:18 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with url parameter' do
|
|
|
|
let(:options) { { user: user, url: '/over/the/rainbow.png' } }
|
|
|
|
|
|
|
|
it 'uses provided url' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-06-02 03:42:18 -04:00
|
|
|
alt: "#{user.name}'s avatar",
|
2017-09-25 04:13:15 -04:00
|
|
|
src: options[:url],
|
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s16 has-tooltip",
|
|
|
|
title: user.name
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with lazy parameter' do
|
|
|
|
let(:options) { { user: user, lazy: true } }
|
|
|
|
|
|
|
|
it 'adds `lazy` class to class list, sets `data-src` with avatar URL and `src` with placeholder image' do
|
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
|
|
|
alt: "#{user.name}'s avatar",
|
|
|
|
src: LazyImageTagHelper.placeholder_image,
|
2018-02-09 07:07:19 -05:00
|
|
|
data: { container: 'body', src: avatar_icon_for_user(user, 16) },
|
2017-09-25 04:13:15 -04:00
|
|
|
class: "avatar s16 has-tooltip lazy",
|
|
|
|
title: user.name
|
2017-06-02 03:42:18 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-22 17:41:17 -04:00
|
|
|
context 'with has_tooltip parameter' do
|
|
|
|
context 'with has_tooltip set to true' do
|
|
|
|
let(:options) { { user: user, has_tooltip: true } }
|
|
|
|
|
|
|
|
it 'adds has-tooltip' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-08-22 17:41:17 -04:00
|
|
|
alt: "#{user.name}'s avatar",
|
2018-02-09 07:07:19 -05:00
|
|
|
src: avatar_icon_for_user(user, 16),
|
2017-09-25 04:13:15 -04:00
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s16 has-tooltip",
|
|
|
|
title: user.name
|
2017-08-22 17:41:17 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with has_tooltip set to false' do
|
|
|
|
let(:options) { { user: user, has_tooltip: false } }
|
|
|
|
|
|
|
|
it 'does not add has-tooltip or data container' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-08-22 17:41:17 -04:00
|
|
|
alt: "#{user.name}'s avatar",
|
2018-02-09 07:07:19 -05:00
|
|
|
src: avatar_icon_for_user(user, 16),
|
2017-09-25 04:13:15 -04:00
|
|
|
class: "avatar s16",
|
|
|
|
title: user.name
|
2017-08-22 17:41:17 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-06-02 03:42:18 -04:00
|
|
|
context 'with user_name parameter' do
|
|
|
|
let(:options) { { user_name: 'Tinky Winky', user_email: 'no@f.un' } }
|
|
|
|
|
|
|
|
context 'with user parameter' do
|
|
|
|
let(:options) { { user: user, user_name: 'Tinky Winky' } }
|
|
|
|
|
|
|
|
it 'prefers user parameter' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-06-02 03:42:18 -04:00
|
|
|
alt: "#{user.name}'s avatar",
|
2018-02-09 07:07:19 -05:00
|
|
|
src: avatar_icon_for_user(user, 16),
|
2017-09-25 04:13:15 -04:00
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s16 has-tooltip",
|
|
|
|
title: user.name
|
2017-06-02 03:42:18 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'uses user_name and user_email parameter if user is not present' do
|
2017-09-25 04:13:15 -04:00
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
2017-06-02 03:42:18 -04:00
|
|
|
alt: "#{options[:user_name]}'s avatar",
|
2021-03-03 01:11:13 -05:00
|
|
|
src: helper.avatar_icon_for_email(options[:user_email], 16),
|
2017-09-25 04:13:15 -04:00
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s16 has-tooltip",
|
|
|
|
title: options[:user_name]
|
2017-06-02 03:42:18 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2019-08-30 13:26:10 -04:00
|
|
|
|
|
|
|
context 'with only_path parameter set to false' do
|
|
|
|
let(:user_with_avatar) { create(:user, :with_avatar, username: 'foobar') }
|
|
|
|
|
|
|
|
context 'with user parameter' do
|
|
|
|
let(:options) { { user: user_with_avatar, only_path: false } }
|
|
|
|
|
|
|
|
it 'will return avatar with a full path' do
|
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
|
|
|
alt: "#{user_with_avatar.name}'s avatar",
|
|
|
|
src: avatar_icon_for_user(user_with_avatar, 16, only_path: false),
|
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s16 has-tooltip",
|
|
|
|
title: user_with_avatar.name
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with user_name and user_email' do
|
|
|
|
let(:options) { { user_email: user_with_avatar.email, user_name: user_with_avatar.username, only_path: false } }
|
|
|
|
|
|
|
|
it 'will return avatar with a full path' do
|
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
|
|
|
alt: "#{user_with_avatar.username}'s avatar",
|
2021-03-03 01:11:13 -05:00
|
|
|
src: helper.avatar_icon_for_email(user_with_avatar.email, 16, only_path: false),
|
2019-08-30 13:26:10 -04:00
|
|
|
data: { container: 'body' },
|
|
|
|
class: "avatar s16 has-tooltip",
|
|
|
|
title: user_with_avatar.username
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with unregistered email address' do
|
|
|
|
let(:options) { { user_email: "unregistered_email@example.com" } }
|
|
|
|
|
|
|
|
it 'will return default alt text for avatar' do
|
|
|
|
expect(subject).to include("default avatar")
|
|
|
|
end
|
|
|
|
end
|
2017-06-02 03:42:18 -04:00
|
|
|
end
|
2021-04-22 11:09:56 -04:00
|
|
|
|
|
|
|
describe '#avatar_without_link' do
|
|
|
|
let(:options) { { size: 32 } }
|
|
|
|
|
|
|
|
subject { helper.avatar_without_link(resource, options) }
|
|
|
|
|
|
|
|
context 'with users' do
|
|
|
|
let(:resource) { user }
|
|
|
|
|
|
|
|
it 'displays user avatar' do
|
|
|
|
is_expected.to eq tag(
|
|
|
|
:img,
|
|
|
|
alt: "#{user.name}'s avatar",
|
|
|
|
src: avatar_icon_for_user(user, 32),
|
|
|
|
data: { container: 'body' },
|
|
|
|
class: 'avatar s32 has-tooltip',
|
|
|
|
title: user.name
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with groups' do
|
|
|
|
let(:resource) { build_stubbed(:group, name: 'foo') }
|
|
|
|
|
|
|
|
it 'displays group avatar' do
|
2021-04-28 14:10:12 -04:00
|
|
|
is_expected.to match(%r{<span class="avatar identicon bg\d+ s32">F</span>})
|
2021-04-22 11:09:56 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-03-23 04:43:34 -04:00
|
|
|
end
|