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 commitComp from '~/vue_shared/components/commit.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
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 component;
let CommitComponent;
let wrapper;
beforeEach(() => {
CommitComponent = Vue.extend(commitComp);
});
const findUserAvatar = () => wrapper.find(UserAvatarLink);
const createComponent = propsData => {
wrapper = shallowMount(CommitComponent, {
propsData,
sync: false,
});
};
afterEach(() => {
component.$destroy();
wrapper.destroy();
});
it('should render a fork icon if it does not represent a tag', () => {
component = mountComponent(CommitComponent, {
createComponent({
tag: false,
commitRef: {
name: 'master',
......@@ -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', () => {
......@@ -56,68 +66,51 @@ describe('Commit component', () => {
username: 'jschatz1',
},
};
component = mountComponent(CommitComponent, props);
createComponent(props);
});
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', () => {
expect(component.$el.querySelector('.ref-name').getAttribute('href')).toEqual(
props.commitRef.ref_url,
);
expect(wrapper.find('.ref-name').attributes('href')).toBe(props.commitRef.ref_url);
});
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', () => {
expect(component.$el.querySelector('.commit-sha').getAttribute('href')).toEqual(
props.commitUrl,
);
expect(wrapper.find('.commit-sha').attributes('href')).toEqual(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', () => {
expect(
component.$el.querySelector('.js-commit-icon use').getAttribute('xlink:href'),
).toContain('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', () => {
expect(
component.$el.querySelector('.commit-title .avatar-image-container').getAttribute('href'),
).toEqual(props.author.path);
const userAvatar = findUserAvatar();
expect(userAvatar.props('linkHref')).toBe(props.author.path);
});
it('Should render the author avatar with title and alt attributes', () => {
expect(
component.$el
.querySelector('.commit-title .avatar-image-container .js-user-avatar-image-toolip')
.textContent.trim(),
).toContain(props.author.username);
expect(
component.$el
.querySelector('.commit-title .avatar-image-container img')
.getAttribute('alt'),
).toContain(`${props.author.username}'s avatar`);
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(component.$el.querySelector('a.commit-row-message').getAttribute('href')).toEqual(
props.commitUrl,
);
expect(wrapper.find('.commit-row-message').attributes('href')).toEqual(props.commitUrl);
expect(component.$el.querySelector('a.commit-row-message').textContent).toContain(
props.title,
);
expect(wrapper.find('.commit-row-message').text()).toContain(props.title);
});
});
......@@ -136,9 +129,9 @@ describe('Commit component', () => {
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",
);
});
......@@ -159,16 +152,16 @@ describe('Commit component', () => {
author: {},
};
component = mountComponent(CommitComponent, props);
const refEl = component.$el.querySelector('.ref-name');
createComponent(props);
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', () => {
author: {},
};
component = mountComponent(CommitComponent, props);
const refEl = component.$el.querySelector('.ref-name');
createComponent(props);
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', () => {
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 mountComponent from 'spec/helpers/vue_mount_component_helper';
import UserPopover from '~/vue_shared/components/user_popover/user_popover.vue';
import { mount } from '@vue/test-utils';
const DEFAULT_PROPS = {
loaded: true,
......@@ -14,58 +13,62 @@ const DEFAULT_PROPS = {
},
};
const UserPopover = Vue.extend(userPopover);
describe('User Popover Component', () => {
const fixtureTemplate = 'merge_requests/diff_comment.html';
preloadFixtures(fixtureTemplate);
let vm;
let wrapper;
beforeEach(() => {
loadFixtures(fixtureTemplate);
});
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
describe('Empty', () => {
beforeEach(() => {
vm = mountComponent(UserPopover, {
target: document.querySelector('.js-user-link'),
user: {
name: null,
username: null,
location: null,
bio: null,
organization: null,
status: null,
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(vm.$el.querySelectorAll('.animation-container').length).toBe(4);
expect(wrapper.findAll('.animation-container').length).toBe(4);
});
});
describe('basic data', () => {
it('should show basic fields', () => {
vm = mountComponent(UserPopover, {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
wrapper = mount(UserPopover, {
propsData: {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
},
sync: false,
});
expect(vm.$el.textContent).toContain(DEFAULT_PROPS.user.name);
expect(vm.$el.textContent).toContain(DEFAULT_PROPS.user.username);
expect(vm.$el.textContent).toContain(DEFAULT_PROPS.user.location);
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 = 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', () => {
const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.bio = 'Engineer';
vm = mountComponent(UserPopover, {
...testProps,
target: document.querySelector('.js-user-link'),
wrapper = mount(UserPopover, {
propsData: {
...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', () => {
const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.organization = 'GitLab';
vm = mountComponent(UserPopover, {
...testProps,
target: document.querySelector('.js-user-link'),
wrapper = mount(UserPopover, {
propsData: {
...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', () => {
......@@ -99,13 +108,16 @@ describe('User Popover Component', () => {
testProps.user.bio = 'Engineer';
testProps.user.organization = 'GitLab';
vm = mountComponent(UserPopover, {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
wrapper = mount(UserPopover, {
propsData: {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
},
sync: false,
});
expect(vm.$el.querySelector('.js-bio').textContent).toContain('Engineer');
expect(vm.$el.querySelector('.js-organization').textContent).toContain('GitLab');
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', () => {
......@@ -113,27 +125,28 @@ describe('User Popover Component', () => {
testProps.user.bio = 'Manager & Team Lead';
testProps.user.organization = 'Me & my <funky> Company';
vm = mountComponent(UserPopover, {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
wrapper = mount(UserPopover, {
propsData: {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
},
sync: false,
});
expect(vm.$el.querySelector('.js-bio').textContent).toContain('Manager & Team Lead');
expect(vm.$el.querySelector('.js-organization').textContent).toContain(
'Me & my <funky> Company',
);
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 = 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', () => {
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', () => {
const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.status = { message_html: 'Hello World' };
vm = mountComponent(UserPopover, {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
wrapper = mount(UserPopover, {
propsData: {
...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', () => {
const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.status = { emoji: 'basketball_player', message_html: 'Hello World' };
vm = mountComponent(UserPopover, {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
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(vm.$el.textContent).toContain('Hello World');
expect(vm.$el.innerHTML).toContain('<gl-emoji data-name="basketball_player"');
expect(wrapper.text()).toContain('Hello World');
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