summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_shared
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-31 00:07:00 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-31 00:07:00 +0000
commitfd0691c6c0dc16ddada016af08c47a28614e888d (patch)
tree17e3da2d636967070bbd7b2039d3a5ce1adf1770 /spec/frontend/vue_shared
parent0f0a8be306e7e0cd5693f57414de351808c41db9 (diff)
downloadgitlab-ce-fd0691c6c0dc16ddada016af08c47a28614e888d.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/vue_shared')
-rw-r--r--spec/frontend/vue_shared/components/commit_spec.js227
-rw-r--r--spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js108
-rw-r--r--spec/frontend/vue_shared/components/user_popover/user_popover_spec.js186
3 files changed, 521 insertions, 0 deletions
diff --git a/spec/frontend/vue_shared/components/commit_spec.js b/spec/frontend/vue_shared/components/commit_spec.js
new file mode 100644
index 00000000000..77d8e00cf00
--- /dev/null
+++ b/spec/frontend/vue_shared/components/commit_spec.js
@@ -0,0 +1,227 @@
+import { shallowMount } from '@vue/test-utils';
+import CommitComponent from '~/vue_shared/components/commit.vue';
+import Icon from '~/vue_shared/components/icon.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+
+describe('Commit component', () => {
+ let props;
+ let wrapper;
+
+ const findUserAvatar = () => wrapper.find(UserAvatarLink);
+
+ const createComponent = propsData => {
+ wrapper = shallowMount(CommitComponent, {
+ propsData,
+ sync: false,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render a fork icon if it does not represent a tag', () => {
+ createComponent({
+ tag: false,
+ commitRef: {
+ name: 'master',
+ ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
+ },
+ commitUrl:
+ 'https://gitlab.com/gitlab-org/gitlab-foss/commit/b7836eddf62d663c665769e1b0960197fd215067',
+ shortSha: 'b7836edd',
+ title: 'Commit message',
+ author: {
+ avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png',
+ web_url: 'https://gitlab.com/jschatz1',
+ path: '/jschatz1',
+ username: 'jschatz1',
+ },
+ });
+
+ expect(
+ wrapper
+ .find('.icon-container')
+ .find(Icon)
+ .exists(),
+ ).toBe(true);
+ });
+
+ describe('Given all the props', () => {
+ beforeEach(() => {
+ props = {
+ tag: true,
+ commitRef: {
+ name: 'master',
+ ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
+ },
+ commitUrl:
+ 'https://gitlab.com/gitlab-org/gitlab-foss/commit/b7836eddf62d663c665769e1b0960197fd215067',
+ shortSha: 'b7836edd',
+ title: 'Commit message',
+ author: {
+ avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png',
+ web_url: 'https://gitlab.com/jschatz1',
+ path: '/jschatz1',
+ username: 'jschatz1',
+ },
+ };
+ createComponent(props);
+ });
+
+ it('should render a tag icon if it represents a tag', () => {
+ expect(wrapper.find('icon-stub[name="tag"]').exists()).toBe(true);
+ });
+
+ it('should render a link to the ref url', () => {
+ expect(wrapper.find('.ref-name').attributes('href')).toBe(props.commitRef.ref_url);
+ });
+
+ it('should render the ref name', () => {
+ expect(wrapper.find('.ref-name').text()).toContain(props.commitRef.name);
+ });
+
+ it('should render the commit short sha with a link to the commit url', () => {
+ expect(wrapper.find('.commit-sha').attributes('href')).toEqual(props.commitUrl);
+
+ expect(wrapper.find('.commit-sha').text()).toContain(props.shortSha);
+ });
+
+ it('should render icon for commit', () => {
+ expect(wrapper.find('icon-stub[name="commit"]').exists()).toBe(true);
+ });
+
+ describe('Given commit title and author props', () => {
+ it('should render a link to the author profile', () => {
+ const userAvatar = findUserAvatar();
+
+ expect(userAvatar.props('linkHref')).toBe(props.author.path);
+ });
+
+ it('Should render the author avatar with title and alt attributes', () => {
+ const userAvatar = findUserAvatar();
+
+ expect(userAvatar.exists()).toBe(true);
+
+ expect(userAvatar.props('imgAlt')).toBe(`${props.author.username}'s avatar`);
+ });
+ });
+
+ it('should render the commit title', () => {
+ expect(wrapper.find('.commit-row-message').attributes('href')).toEqual(props.commitUrl);
+
+ expect(wrapper.find('.commit-row-message').text()).toContain(props.title);
+ });
+ });
+
+ describe('When commit title is not provided', () => {
+ it('should render default message', () => {
+ props = {
+ tag: false,
+ commitRef: {
+ name: 'master',
+ ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
+ },
+ commitUrl:
+ 'https://gitlab.com/gitlab-org/gitlab-foss/commit/b7836eddf62d663c665769e1b0960197fd215067',
+ shortSha: 'b7836edd',
+ title: null,
+ author: {},
+ };
+
+ createComponent(props);
+
+ expect(wrapper.find('.commit-title span').text()).toContain(
+ "Can't find HEAD commit for this branch",
+ );
+ });
+ });
+
+ describe('When commit ref is provided, but merge ref is not', () => {
+ it('should render the commit ref', () => {
+ props = {
+ tag: false,
+ commitRef: {
+ name: 'master',
+ ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
+ },
+ commitUrl:
+ 'https://gitlab.com/gitlab-org/gitlab-foss/commit/b7836eddf62d663c665769e1b0960197fd215067',
+ shortSha: 'b7836edd',
+ title: null,
+ author: {},
+ };
+
+ createComponent(props);
+ const refEl = wrapper.find('.ref-name');
+
+ expect(refEl.text()).toContain('master');
+
+ expect(refEl.attributes('href')).toBe(props.commitRef.ref_url);
+
+ expect(refEl.attributes('data-original-title')).toBe(props.commitRef.name);
+
+ expect(wrapper.find('icon-stub[name="branch"]').exists()).toBe(true);
+ });
+ });
+
+ describe('When both commit and merge ref are provided', () => {
+ it('should render the merge ref', () => {
+ props = {
+ tag: false,
+ commitRef: {
+ name: 'master',
+ ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
+ },
+ commitUrl:
+ 'https://gitlab.com/gitlab-org/gitlab-foss/commit/b7836eddf62d663c665769e1b0960197fd215067',
+ mergeRequestRef: {
+ iid: 1234,
+ path: 'https://example.com/path/to/mr',
+ title: 'Test MR',
+ },
+ shortSha: 'b7836edd',
+ title: null,
+ author: {},
+ };
+
+ createComponent(props);
+ const refEl = wrapper.find('.ref-name');
+
+ expect(refEl.text()).toContain('1234');
+
+ expect(refEl.attributes('href')).toBe(props.mergeRequestRef.path);
+
+ expect(refEl.attributes('data-original-title')).toBe(props.mergeRequestRef.title);
+
+ expect(wrapper.find('icon-stub[name="git-merge"]').exists()).toBe(true);
+ });
+ });
+
+ describe('When showRefInfo === false', () => {
+ it('should not render any ref info', () => {
+ props = {
+ tag: false,
+ commitRef: {
+ name: 'master',
+ ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
+ },
+ commitUrl:
+ 'https://gitlab.com/gitlab-org/gitlab-foss/commit/b7836eddf62d663c665769e1b0960197fd215067',
+ mergeRequestRef: {
+ iid: 1234,
+ path: '/path/to/mr',
+ title: 'Test MR',
+ },
+ shortSha: 'b7836edd',
+ title: null,
+ author: {},
+ showRefInfo: false,
+ };
+
+ createComponent(props);
+
+ expect(wrapper.find('.ref-name').exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
new file mode 100644
index 00000000000..2f87359a4a6
--- /dev/null
+++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js
@@ -0,0 +1,108 @@
+import { shallowMount } from '@vue/test-utils';
+import { placeholderImage } from '~/lazy_loader';
+import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
+import defaultAvatarUrl from 'images/no_avatar.png';
+
+jest.mock('images/no_avatar.png', () => 'default-avatar-url');
+
+const DEFAULT_PROPS = {
+ size: 99,
+ imgSrc: 'myavatarurl.com',
+ imgAlt: 'mydisplayname',
+ cssClasses: 'myextraavatarclass',
+ tooltipText: 'tooltip text',
+ tooltipPlacement: 'bottom',
+};
+
+describe('User Avatar Image Component', () => {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Initialization', () => {
+ beforeEach(() => {
+ wrapper = shallowMount(UserAvatarImage, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ },
+ sync: false,
+ });
+ });
+
+ it('should have <img> as a child element', () => {
+ const imageElement = wrapper.find('img');
+
+ expect(imageElement.exists()).toBe(true);
+ expect(imageElement.attributes('src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
+ expect(imageElement.attributes('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
+ expect(imageElement.attributes('alt')).toBe(DEFAULT_PROPS.imgAlt);
+ });
+
+ it('should properly render img css', () => {
+ const classes = wrapper.find('img').classes();
+ expect(classes).toEqual(expect.arrayContaining(['avatar', 's99', DEFAULT_PROPS.cssClasses]));
+ expect(classes).not.toContain('lazy');
+ });
+ });
+
+ describe('Initialization when lazy', () => {
+ beforeEach(() => {
+ wrapper = shallowMount(UserAvatarImage, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ lazy: true,
+ },
+ sync: false,
+ });
+ });
+
+ it('should add lazy attributes', () => {
+ const imageElement = wrapper.find('img');
+
+ expect(imageElement.classes()).toContain('lazy');
+ expect(imageElement.attributes('src')).toBe(placeholderImage);
+ expect(imageElement.attributes('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
+ });
+ });
+
+ describe('Initialization without src', () => {
+ beforeEach(() => {
+ wrapper = shallowMount(UserAvatarImage, { sync: false });
+ });
+
+ it('should have default avatar image', () => {
+ const imageElement = wrapper.find('img');
+
+ expect(imageElement.attributes('src')).toBe(`${defaultAvatarUrl}?width=20`);
+ });
+ });
+
+ describe('dynamic tooltip content', () => {
+ const props = DEFAULT_PROPS;
+ const slots = {
+ default: ['Action!'],
+ };
+
+ beforeEach(() => {
+ wrapper = shallowMount(UserAvatarImage, { propsData: { props }, slots, sync: false });
+ });
+
+ it('renders the tooltip slot', () => {
+ expect(wrapper.find('.js-user-avatar-image-toolip').exists()).toBe(true);
+ });
+
+ it('renders the tooltip content', () => {
+ expect(wrapper.find('.js-user-avatar-image-toolip').text()).toContain(slots.default[0]);
+ });
+
+ it('does not render tooltip data attributes for on avatar image', () => {
+ const avatarImg = wrapper.find('img');
+
+ expect(avatarImg.attributes('data-original-title')).toBeFalsy();
+ expect(avatarImg.attributes('data-placement')).not.toBeDefined();
+ expect(avatarImg.attributes('data-container')).not.toBeDefined();
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
new file mode 100644
index 00000000000..fc2eb6329b0
--- /dev/null
+++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
@@ -0,0 +1,186 @@
+import UserPopover from '~/vue_shared/components/user_popover/user_popover.vue';
+import { mount } from '@vue/test-utils';
+
+const DEFAULT_PROPS = {
+ loaded: true,
+ user: {
+ username: 'root',
+ name: 'Administrator',
+ location: 'Vienna',
+ bio: null,
+ organization: null,
+ status: null,
+ },
+};
+
+describe('User Popover Component', () => {
+ const fixtureTemplate = 'merge_requests/diff_comment.html';
+ preloadFixtures(fixtureTemplate);
+
+ let wrapper;
+
+ beforeEach(() => {
+ loadFixtures(fixtureTemplate);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Empty', () => {
+ beforeEach(() => {
+ wrapper = mount(UserPopover, {
+ propsData: {
+ target: document.querySelector('.js-user-link'),
+ user: {
+ name: null,
+ username: null,
+ location: null,
+ bio: null,
+ organization: null,
+ status: null,
+ },
+ },
+ sync: false,
+ });
+ });
+
+ it('should return skeleton loaders', () => {
+ expect(wrapper.findAll('.animation-container').length).toBe(4);
+ });
+ });
+
+ describe('basic data', () => {
+ it('should show basic fields', () => {
+ wrapper = mount(UserPopover, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ target: document.querySelector('.js-user-link'),
+ },
+ sync: false,
+ });
+
+ expect(wrapper.text()).toContain(DEFAULT_PROPS.user.name);
+ expect(wrapper.text()).toContain(DEFAULT_PROPS.user.username);
+ expect(wrapper.text()).toContain(DEFAULT_PROPS.user.location);
+ });
+
+ it('shows icon for location', () => {
+ const iconEl = wrapper.find('.js-location svg');
+
+ expect(iconEl.find('use').element.getAttribute('xlink:href')).toContain('location');
+ });
+ });
+
+ describe('job data', () => {
+ it('should show only bio if no organization is available', () => {
+ const testProps = Object.assign({}, DEFAULT_PROPS);
+ testProps.user.bio = 'Engineer';
+
+ wrapper = mount(UserPopover, {
+ propsData: {
+ ...testProps,
+ target: document.querySelector('.js-user-link'),
+ },
+ sync: false,
+ });
+
+ expect(wrapper.text()).toContain('Engineer');
+ });
+
+ it('should show only organization if no bio is available', () => {
+ const testProps = Object.assign({}, DEFAULT_PROPS);
+ testProps.user.organization = 'GitLab';
+
+ wrapper = mount(UserPopover, {
+ propsData: {
+ ...testProps,
+ target: document.querySelector('.js-user-link'),
+ },
+ sync: false,
+ });
+
+ expect(wrapper.text()).toContain('GitLab');
+ });
+
+ it('should display bio and organization in separate lines', () => {
+ const testProps = Object.assign({}, DEFAULT_PROPS);
+ testProps.user.bio = 'Engineer';
+ testProps.user.organization = 'GitLab';
+
+ wrapper = mount(UserPopover, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ target: document.querySelector('.js-user-link'),
+ },
+ sync: false,
+ });
+
+ expect(wrapper.find('.js-bio').text()).toContain('Engineer');
+ expect(wrapper.find('.js-organization').text()).toContain('GitLab');
+ });
+
+ it('should not encode special characters in bio and organization', () => {
+ const testProps = Object.assign({}, DEFAULT_PROPS);
+ testProps.user.bio = 'Manager & Team Lead';
+ testProps.user.organization = 'Me & my <funky> Company';
+
+ wrapper = mount(UserPopover, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ target: document.querySelector('.js-user-link'),
+ },
+ sync: false,
+ });
+
+ expect(wrapper.find('.js-bio').text()).toContain('Manager & Team Lead');
+ expect(wrapper.find('.js-organization').text()).toContain('Me & my <funky> Company');
+ });
+
+ it('shows icon for bio', () => {
+ const iconEl = wrapper.find('.js-bio svg');
+
+ expect(iconEl.find('use').element.getAttribute('xlink:href')).toContain('profile');
+ });
+
+ it('shows icon for organization', () => {
+ const iconEl = wrapper.find('.js-organization svg');
+
+ expect(iconEl.find('use').element.getAttribute('xlink:href')).toContain('work');
+ });
+ });
+
+ describe('status data', () => {
+ it('should show only message', () => {
+ const testProps = Object.assign({}, DEFAULT_PROPS);
+ testProps.user.status = { message_html: 'Hello World' };
+
+ wrapper = mount(UserPopover, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ target: document.querySelector('.js-user-link'),
+ },
+ sync: false,
+ });
+
+ expect(wrapper.text()).toContain('Hello World');
+ });
+
+ it('should show message and emoji', () => {
+ const testProps = Object.assign({}, DEFAULT_PROPS);
+ testProps.user.status = { emoji: 'basketball_player', message_html: 'Hello World' };
+
+ wrapper = mount(UserPopover, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ target: document.querySelector('.js-user-link'),
+ status: { emoji: 'basketball_player', message_html: 'Hello World' },
+ },
+ sync: false,
+ });
+
+ expect(wrapper.text()).toContain('Hello World');
+ expect(wrapper.html()).toContain('<gl-emoji data-name="basketball_player"');
+ });
+ });
+});