Commit 05ac0e81 authored by Paul Gascou-Vaillancourt's avatar Paul Gascou-Vaillancourt Committed by Natalia Tepluhina

Migrate vue share components specs to Jest & VTU

Migrated vue shared components specs that rely on tooltips
to Jest & Vue Test Utils
parent 9c9b6a40
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import commitComp from '~/vue_shared/components/commit.vue'; import CommitComponent from '~/vue_shared/components/commit.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
describe('Commit component', () => { describe('Commit component', () => {
let props; let props;
let component; let wrapper;
let CommitComponent;
beforeEach(() => { const findUserAvatar = () => wrapper.find(UserAvatarLink);
CommitComponent = Vue.extend(commitComp);
}); const createComponent = propsData => {
wrapper = shallowMount(CommitComponent, {
propsData,
sync: false,
});
};
afterEach(() => { afterEach(() => {
component.$destroy(); wrapper.destroy();
}); });
it('should render a fork icon if it does not represent a tag', () => { it('should render a fork icon if it does not represent a tag', () => {
component = mountComponent(CommitComponent, { createComponent({
tag: false, tag: false,
commitRef: { commitRef: {
name: 'master', name: 'master',
...@@ -34,7 +39,12 @@ describe('Commit component', () => { ...@@ -34,7 +39,12 @@ describe('Commit component', () => {
}, },
}); });
expect(component.$el.querySelector('.icon-container').children).toContain('svg'); expect(
wrapper
.find('.icon-container')
.find(Icon)
.exists(),
).toBe(true);
}); });
describe('Given all the props', () => { describe('Given all the props', () => {
...@@ -56,68 +66,51 @@ describe('Commit component', () => { ...@@ -56,68 +66,51 @@ describe('Commit component', () => {
username: 'jschatz1', username: 'jschatz1',
}, },
}; };
createComponent(props);
component = mountComponent(CommitComponent, props);
}); });
it('should render a tag icon if it represents a tag', () => { it('should render a tag icon if it represents a tag', () => {
expect(component.$el.querySelector('.icon-container svg.ic-tag')).not.toBeNull(); expect(wrapper.find('icon-stub[name="tag"]').exists()).toBe(true);
}); });
it('should render a link to the ref url', () => { it('should render a link to the ref url', () => {
expect(component.$el.querySelector('.ref-name').getAttribute('href')).toEqual( expect(wrapper.find('.ref-name').attributes('href')).toBe(props.commitRef.ref_url);
props.commitRef.ref_url,
);
}); });
it('should render the ref name', () => { it('should render the ref name', () => {
expect(component.$el.querySelector('.ref-name').textContent).toContain(props.commitRef.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', () => { it('should render the commit short sha with a link to the commit url', () => {
expect(component.$el.querySelector('.commit-sha').getAttribute('href')).toEqual( expect(wrapper.find('.commit-sha').attributes('href')).toEqual(props.commitUrl);
props.commitUrl,
);
expect(component.$el.querySelector('.commit-sha').textContent).toContain(props.shortSha); expect(wrapper.find('.commit-sha').text()).toContain(props.shortSha);
}); });
it('should render icon for commit', () => { it('should render icon for commit', () => {
expect( expect(wrapper.find('icon-stub[name="commit"]').exists()).toBe(true);
component.$el.querySelector('.js-commit-icon use').getAttribute('xlink:href'),
).toContain('commit');
}); });
describe('Given commit title and author props', () => { describe('Given commit title and author props', () => {
it('should render a link to the author profile', () => { it('should render a link to the author profile', () => {
expect( const userAvatar = findUserAvatar();
component.$el.querySelector('.commit-title .avatar-image-container').getAttribute('href'),
).toEqual(props.author.path); expect(userAvatar.props('linkHref')).toBe(props.author.path);
}); });
it('Should render the author avatar with title and alt attributes', () => { it('Should render the author avatar with title and alt attributes', () => {
expect( const userAvatar = findUserAvatar();
component.$el
.querySelector('.commit-title .avatar-image-container .js-user-avatar-image-toolip') expect(userAvatar.exists()).toBe(true);
.textContent.trim(),
).toContain(props.author.username); expect(userAvatar.props('imgAlt')).toBe(`${props.author.username}'s avatar`);
expect(
component.$el
.querySelector('.commit-title .avatar-image-container img')
.getAttribute('alt'),
).toContain(`${props.author.username}'s avatar`);
}); });
}); });
it('should render the commit title', () => { it('should render the commit title', () => {
expect(component.$el.querySelector('a.commit-row-message').getAttribute('href')).toEqual( expect(wrapper.find('.commit-row-message').attributes('href')).toEqual(props.commitUrl);
props.commitUrl,
);
expect(component.$el.querySelector('a.commit-row-message').textContent).toContain( expect(wrapper.find('.commit-row-message').text()).toContain(props.title);
props.title,
);
}); });
}); });
...@@ -136,9 +129,9 @@ describe('Commit component', () => { ...@@ -136,9 +129,9 @@ describe('Commit component', () => {
author: {}, author: {},
}; };
component = mountComponent(CommitComponent, props); createComponent(props);
expect(component.$el.querySelector('.commit-title span').textContent).toContain( expect(wrapper.find('.commit-title span').text()).toContain(
"Can't find HEAD commit for this branch", "Can't find HEAD commit for this branch",
); );
}); });
...@@ -159,16 +152,16 @@ describe('Commit component', () => { ...@@ -159,16 +152,16 @@ describe('Commit component', () => {
author: {}, author: {},
}; };
component = mountComponent(CommitComponent, props); createComponent(props);
const refEl = component.$el.querySelector('.ref-name'); const refEl = wrapper.find('.ref-name');
expect(refEl.textContent).toContain('master'); expect(refEl.text()).toContain('master');
expect(refEl.href).toBe(props.commitRef.ref_url); expect(refEl.attributes('href')).toBe(props.commitRef.ref_url);
expect(refEl.getAttribute('data-original-title')).toBe(props.commitRef.name); expect(refEl.attributes('data-original-title')).toBe(props.commitRef.name);
expect(component.$el.querySelector('.icon-container .ic-branch')).not.toBeNull(); expect(wrapper.find('icon-stub[name="branch"]').exists()).toBe(true);
}); });
}); });
...@@ -192,16 +185,16 @@ describe('Commit component', () => { ...@@ -192,16 +185,16 @@ describe('Commit component', () => {
author: {}, author: {},
}; };
component = mountComponent(CommitComponent, props); createComponent(props);
const refEl = component.$el.querySelector('.ref-name'); const refEl = wrapper.find('.ref-name');
expect(refEl.textContent).toContain('1234'); expect(refEl.text()).toContain('1234');
expect(refEl.href).toBe(props.mergeRequestRef.path); expect(refEl.attributes('href')).toBe(props.mergeRequestRef.path);
expect(refEl.getAttribute('data-original-title')).toBe(props.mergeRequestRef.title); expect(refEl.attributes('data-original-title')).toBe(props.mergeRequestRef.title);
expect(component.$el.querySelector('.icon-container .ic-git-merge')).not.toBeNull(); expect(wrapper.find('icon-stub[name="git-merge"]').exists()).toBe(true);
}); });
}); });
...@@ -226,9 +219,9 @@ describe('Commit component', () => { ...@@ -226,9 +219,9 @@ describe('Commit component', () => {
showRefInfo: false, showRefInfo: false,
}; };
component = mountComponent(CommitComponent, props); createComponent(props);
expect(component.$el.querySelector('.ref-name')).toBeNull(); expect(wrapper.find('.ref-name').exists()).toBe(false);
}); });
}); });
}); });
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();
});
});
});
import Vue from 'vue'; import UserPopover from '~/vue_shared/components/user_popover/user_popover.vue';
import userPopover from '~/vue_shared/components/user_popover/user_popover.vue'; import { mount } from '@vue/test-utils';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
const DEFAULT_PROPS = { const DEFAULT_PROPS = {
loaded: true, loaded: true,
...@@ -14,58 +13,62 @@ const DEFAULT_PROPS = { ...@@ -14,58 +13,62 @@ const DEFAULT_PROPS = {
}, },
}; };
const UserPopover = Vue.extend(userPopover);
describe('User Popover Component', () => { describe('User Popover Component', () => {
const fixtureTemplate = 'merge_requests/diff_comment.html'; const fixtureTemplate = 'merge_requests/diff_comment.html';
preloadFixtures(fixtureTemplate); preloadFixtures(fixtureTemplate);
let vm; let wrapper;
beforeEach(() => { beforeEach(() => {
loadFixtures(fixtureTemplate); loadFixtures(fixtureTemplate);
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
describe('Empty', () => { describe('Empty', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
target: document.querySelector('.js-user-link'), propsData: {
user: { target: document.querySelector('.js-user-link'),
name: null, user: {
username: null, name: null,
location: null, username: null,
bio: null, location: null,
organization: null, bio: null,
status: null, organization: null,
status: null,
},
}, },
sync: false,
}); });
}); });
it('should return skeleton loaders', () => { it('should return skeleton loaders', () => {
expect(vm.$el.querySelectorAll('.animation-container').length).toBe(4); expect(wrapper.findAll('.animation-container').length).toBe(4);
}); });
}); });
describe('basic data', () => { describe('basic data', () => {
it('should show basic fields', () => { it('should show basic fields', () => {
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
...DEFAULT_PROPS, propsData: {
target: document.querySelector('.js-user-link'), ...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
},
sync: false,
}); });
expect(vm.$el.textContent).toContain(DEFAULT_PROPS.user.name); expect(wrapper.text()).toContain(DEFAULT_PROPS.user.name);
expect(vm.$el.textContent).toContain(DEFAULT_PROPS.user.username); expect(wrapper.text()).toContain(DEFAULT_PROPS.user.username);
expect(vm.$el.textContent).toContain(DEFAULT_PROPS.user.location); expect(wrapper.text()).toContain(DEFAULT_PROPS.user.location);
}); });
it('shows icon for location', () => { it('shows icon for location', () => {
const iconEl = vm.$el.querySelector('.js-location svg'); const iconEl = wrapper.find('.js-location svg');
expect(iconEl.querySelector('use').getAttribute('xlink:href')).toContain('location'); expect(iconEl.find('use').element.getAttribute('xlink:href')).toContain('location');
}); });
}); });
...@@ -74,24 +77,30 @@ describe('User Popover Component', () => { ...@@ -74,24 +77,30 @@ describe('User Popover Component', () => {
const testProps = Object.assign({}, DEFAULT_PROPS); const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.bio = 'Engineer'; testProps.user.bio = 'Engineer';
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
...testProps, propsData: {
target: document.querySelector('.js-user-link'), ...testProps,
target: document.querySelector('.js-user-link'),
},
sync: false,
}); });
expect(vm.$el.textContent).toContain('Engineer'); expect(wrapper.text()).toContain('Engineer');
}); });
it('should show only organization if no bio is available', () => { it('should show only organization if no bio is available', () => {
const testProps = Object.assign({}, DEFAULT_PROPS); const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.organization = 'GitLab'; testProps.user.organization = 'GitLab';
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
...testProps, propsData: {
target: document.querySelector('.js-user-link'), ...testProps,
target: document.querySelector('.js-user-link'),
},
sync: false,
}); });
expect(vm.$el.textContent).toContain('GitLab'); expect(wrapper.text()).toContain('GitLab');
}); });
it('should display bio and organization in separate lines', () => { it('should display bio and organization in separate lines', () => {
...@@ -99,13 +108,16 @@ describe('User Popover Component', () => { ...@@ -99,13 +108,16 @@ describe('User Popover Component', () => {
testProps.user.bio = 'Engineer'; testProps.user.bio = 'Engineer';
testProps.user.organization = 'GitLab'; testProps.user.organization = 'GitLab';
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
...DEFAULT_PROPS, propsData: {
target: document.querySelector('.js-user-link'), ...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
},
sync: false,
}); });
expect(vm.$el.querySelector('.js-bio').textContent).toContain('Engineer'); expect(wrapper.find('.js-bio').text()).toContain('Engineer');
expect(vm.$el.querySelector('.js-organization').textContent).toContain('GitLab'); expect(wrapper.find('.js-organization').text()).toContain('GitLab');
}); });
it('should not encode special characters in bio and organization', () => { it('should not encode special characters in bio and organization', () => {
...@@ -113,27 +125,28 @@ describe('User Popover Component', () => { ...@@ -113,27 +125,28 @@ describe('User Popover Component', () => {
testProps.user.bio = 'Manager & Team Lead'; testProps.user.bio = 'Manager & Team Lead';
testProps.user.organization = 'Me & my <funky> Company'; testProps.user.organization = 'Me & my <funky> Company';
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
...DEFAULT_PROPS, propsData: {
target: document.querySelector('.js-user-link'), ...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
},
sync: false,
}); });
expect(vm.$el.querySelector('.js-bio').textContent).toContain('Manager & Team Lead'); expect(wrapper.find('.js-bio').text()).toContain('Manager & Team Lead');
expect(vm.$el.querySelector('.js-organization').textContent).toContain( expect(wrapper.find('.js-organization').text()).toContain('Me & my <funky> Company');
'Me & my <funky> Company',
);
}); });
it('shows icon for bio', () => { it('shows icon for bio', () => {
const iconEl = vm.$el.querySelector('.js-bio svg'); const iconEl = wrapper.find('.js-bio svg');
expect(iconEl.querySelector('use').getAttribute('xlink:href')).toContain('profile'); expect(iconEl.find('use').element.getAttribute('xlink:href')).toContain('profile');
}); });
it('shows icon for organization', () => { it('shows icon for organization', () => {
const iconEl = vm.$el.querySelector('.js-organization svg'); const iconEl = wrapper.find('.js-organization svg');
expect(iconEl.querySelector('use').getAttribute('xlink:href')).toContain('work'); expect(iconEl.find('use').element.getAttribute('xlink:href')).toContain('work');
}); });
}); });
...@@ -142,26 +155,32 @@ describe('User Popover Component', () => { ...@@ -142,26 +155,32 @@ describe('User Popover Component', () => {
const testProps = Object.assign({}, DEFAULT_PROPS); const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.status = { message_html: 'Hello World' }; testProps.user.status = { message_html: 'Hello World' };
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
...DEFAULT_PROPS, propsData: {
target: document.querySelector('.js-user-link'), ...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
},
sync: false,
}); });
expect(vm.$el.textContent).toContain('Hello World'); expect(wrapper.text()).toContain('Hello World');
}); });
it('should show message and emoji', () => { it('should show message and emoji', () => {
const testProps = Object.assign({}, DEFAULT_PROPS); const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.status = { emoji: 'basketball_player', message_html: 'Hello World' }; testProps.user.status = { emoji: 'basketball_player', message_html: 'Hello World' };
vm = mountComponent(UserPopover, { wrapper = mount(UserPopover, {
...DEFAULT_PROPS, propsData: {
target: document.querySelector('.js-user-link'), ...DEFAULT_PROPS,
status: { emoji: 'basketball_player', message_html: 'Hello World' }, target: document.querySelector('.js-user-link'),
status: { emoji: 'basketball_player', message_html: 'Hello World' },
},
sync: false,
}); });
expect(vm.$el.textContent).toContain('Hello World'); expect(wrapper.text()).toContain('Hello World');
expect(vm.$el.innerHTML).toContain('<gl-emoji data-name="basketball_player"'); expect(wrapper.html()).toContain('<gl-emoji data-name="basketball_player"');
}); });
}); });
}); });
import Vue from 'vue';
import { placeholderImage } from '~/lazy_loader';
import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import mountComponent, { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper';
import defaultAvatarUrl from '~/../images/no_avatar.png';
const DEFAULT_PROPS = {
size: 99,
imgSrc: 'myavatarurl.com',
imgAlt: 'mydisplayname',
cssClasses: 'myextraavatarclass',
tooltipText: 'tooltip text',
tooltipPlacement: 'bottom',
};
describe('User Avatar Image Component', function() {
let vm;
let UserAvatarImage;
beforeEach(() => {
UserAvatarImage = Vue.extend(userAvatarImage);
});
describe('Initialization', function() {
beforeEach(function() {
vm = mountComponent(UserAvatarImage, {
...DEFAULT_PROPS,
}).$mount();
});
it('should return a defined Vue component', function() {
expect(vm).toBeDefined();
});
it('should have <img> as a child element', function() {
const imageElement = vm.$el.querySelector('img');
expect(imageElement).not.toBe(null);
expect(imageElement.getAttribute('src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
expect(imageElement.getAttribute('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
expect(imageElement.getAttribute('alt')).toBe(DEFAULT_PROPS.imgAlt);
});
it('should properly compute avatarSizeClass', function() {
expect(vm.avatarSizeClass).toBe('s99');
});
it('should properly render img css', function() {
const { classList } = vm.$el.querySelector('img');
const containsAvatar = classList.contains('avatar');
const containsSizeClass = classList.contains('s99');
const containsCustomClass = classList.contains(DEFAULT_PROPS.cssClasses);
const lazyClass = classList.contains('lazy');
expect(containsAvatar).toBe(true);
expect(containsSizeClass).toBe(true);
expect(containsCustomClass).toBe(true);
expect(lazyClass).toBe(false);
});
});
describe('Initialization when lazy', function() {
beforeEach(function() {
vm = mountComponent(UserAvatarImage, {
...DEFAULT_PROPS,
lazy: true,
}).$mount();
});
it('should add lazy attributes', function() {
const imageElement = vm.$el.querySelector('img');
const lazyClass = imageElement.classList.contains('lazy');
expect(lazyClass).toBe(true);
expect(imageElement.getAttribute('src')).toBe(placeholderImage);
expect(imageElement.getAttribute('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
});
});
describe('Initialization without src', function() {
beforeEach(function() {
vm = mountComponent(UserAvatarImage);
});
it('should have default avatar image', function() {
const imageElement = vm.$el.querySelector('img');
expect(imageElement.getAttribute('src')).toBe(defaultAvatarUrl);
});
});
describe('dynamic tooltip content', () => {
const props = DEFAULT_PROPS;
const slots = {
default: ['Action!'],
};
beforeEach(() => {
vm = mountComponentWithSlots(UserAvatarImage, { props, slots }).$mount();
});
it('renders the tooltip slot', () => {
expect(vm.$el.querySelector('.js-user-avatar-image-toolip')).not.toBe(null);
});
it('renders the tooltip content', () => {
expect(vm.$el.querySelector('.js-user-avatar-image-toolip').textContent).toContain(
slots.default[0],
);
});
it('does not render tooltip data attributes for on avatar image', () => {
const avatarImg = vm.$el.querySelector('img');
expect(avatarImg.dataset.originalTitle).not.toBeDefined();
expect(avatarImg.dataset.placement).not.toBeDefined();
expect(avatarImg.dataset.container).not.toBeDefined();
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment