Commit 574b1058 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch '194194-spec-js-badges-to-jest' into 'master'

Migrate spec/javascripts/badges/ to Jest

Closes #194194

See merge request gitlab-org/gitlab!25118
parents 3f5729cb c7cc41e8
import Vue from 'vue'; import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import store from '~/badges/store'; import store from '~/badges/store';
import createEmptyBadge from '~/badges/empty_badge'; import createEmptyBadge from '~/badges/empty_badge';
import BadgeForm from '~/badges/components/badge_form.vue'; import BadgeForm from '~/badges/components/badge_form.vue';
import { DUMMY_IMAGE_URL, TEST_HOST } from '../../test_constants'; import { DUMMY_IMAGE_URL, TEST_HOST } from 'helpers/test_constants';
// avoid preview background process // avoid preview background process
BadgeForm.methods.debouncedPreview = () => {}; BadgeForm.methods.debouncedPreview = () => {};
...@@ -41,7 +41,7 @@ describe('BadgeForm component', () => { ...@@ -41,7 +41,7 @@ describe('BadgeForm component', () => {
describe('onCancel', () => { describe('onCancel', () => {
it('calls stopEditing', () => { it('calls stopEditing', () => {
spyOn(vm, 'stopEditing'); jest.spyOn(vm, 'stopEditing').mockImplementation(() => {});
vm.onCancel(); vm.onCancel();
...@@ -68,14 +68,14 @@ describe('BadgeForm component', () => { ...@@ -68,14 +68,14 @@ describe('BadgeForm component', () => {
const expectInvalidInput = inputElementSelector => { const expectInvalidInput = inputElementSelector => {
const inputElement = vm.$el.querySelector(inputElementSelector); const inputElement = vm.$el.querySelector(inputElementSelector);
expect(inputElement).toBeMatchedBy(':invalid'); expect(inputElement.checkValidity()).toBe(false);
const feedbackElement = vm.$el.querySelector(`${inputElementSelector} + .invalid-feedback`); const feedbackElement = vm.$el.querySelector(`${inputElementSelector} + .invalid-feedback`);
expect(feedbackElement).toBeVisible(); expect(feedbackElement).toBeVisible();
}; };
beforeEach(() => { beforeEach(done => {
spyOn(vm, submitAction).and.returnValue(Promise.resolve()); jest.spyOn(vm, submitAction).mockReturnValue(Promise.resolve());
store.replaceState({ store.replaceState({
...store.state, ...store.state,
badgeInAddForm: createEmptyBadge(), badgeInAddForm: createEmptyBadge(),
...@@ -83,9 +83,14 @@ describe('BadgeForm component', () => { ...@@ -83,9 +83,14 @@ describe('BadgeForm component', () => {
isSaving: false, isSaving: false,
}); });
setValue(nameSelector, 'TestBadge'); Vue.nextTick()
setValue(linkUrlSelector, `${TEST_HOST}/link/url`); .then(() => {
setValue(imageUrlSelector, `${window.location.origin}${DUMMY_IMAGE_URL}`); setValue(nameSelector, 'TestBadge');
setValue(linkUrlSelector, `${TEST_HOST}/link/url`);
setValue(imageUrlSelector, `${window.location.origin}${DUMMY_IMAGE_URL}`);
})
.then(done)
.catch(done.fail);
}); });
it('returns immediately if imageUrl is empty', () => { it('returns immediately if imageUrl is empty', () => {
...@@ -131,8 +136,8 @@ describe('BadgeForm component', () => { ...@@ -131,8 +136,8 @@ describe('BadgeForm component', () => {
it(`calls ${submitAction}`, () => { it(`calls ${submitAction}`, () => {
submitForm(); submitForm();
expect(findImageUrlElement()).toBeMatchedBy(':valid'); expect(findImageUrlElement().checkValidity()).toBe(true);
expect(findLinkUrlElement()).toBeMatchedBy(':valid'); expect(findLinkUrlElement().checkValidity()).toBe(true);
expect(vm[submitAction]).toHaveBeenCalled(); expect(vm[submitAction]).toHaveBeenCalled();
}); });
}; };
......
import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants'; import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants';
import store from '~/badges/store'; import store from '~/badges/store';
import BadgeListRow from '~/badges/components/badge_list_row.vue'; import BadgeListRow from '~/badges/components/badge_list_row.vue';
...@@ -40,15 +39,15 @@ describe('BadgeListRow component', () => { ...@@ -40,15 +39,15 @@ describe('BadgeListRow component', () => {
}); });
it('renders the badge name', () => { it('renders the badge name', () => {
expect(vm.$el).toContainText(badge.name); expect(vm.$el.innerText).toMatch(badge.name);
}); });
it('renders the badge link', () => { it('renders the badge link', () => {
expect(vm.$el).toContainText(badge.linkUrl); expect(vm.$el.innerText).toMatch(badge.linkUrl);
}); });
it('renders the badge kind', () => { it('renders the badge kind', () => {
expect(vm.$el).toContainText('Project Badge'); expect(vm.$el.innerText).toMatch('Project Badge');
}); });
it('shows edit and delete buttons', () => { it('shows edit and delete buttons', () => {
...@@ -66,7 +65,7 @@ describe('BadgeListRow component', () => { ...@@ -66,7 +65,7 @@ describe('BadgeListRow component', () => {
}); });
it('calls editBadge when clicking then edit button', () => { it('calls editBadge when clicking then edit button', () => {
spyOn(vm, 'editBadge'); jest.spyOn(vm, 'editBadge').mockImplementation(() => {});
const editButton = vm.$el.querySelector('.table-button-footer button:first-of-type'); const editButton = vm.$el.querySelector('.table-button-footer button:first-of-type');
editButton.click(); editButton.click();
...@@ -75,13 +74,17 @@ describe('BadgeListRow component', () => { ...@@ -75,13 +74,17 @@ describe('BadgeListRow component', () => {
}); });
it('calls updateBadgeInModal and shows modal when clicking then delete button', done => { it('calls updateBadgeInModal and shows modal when clicking then delete button', done => {
spyOn(vm, 'updateBadgeInModal'); jest.spyOn(vm, 'updateBadgeInModal').mockImplementation(() => {});
$('#delete-badge-modal').on('shown.bs.modal', () => done());
const deleteButton = vm.$el.querySelector('.table-button-footer button:last-of-type'); const deleteButton = vm.$el.querySelector('.table-button-footer button:last-of-type');
deleteButton.click(); deleteButton.click();
expect(vm.updateBadgeInModal).toHaveBeenCalled(); Vue.nextTick()
.then(() => {
expect(vm.updateBadgeInModal).toHaveBeenCalled();
})
.then(done)
.catch(done.fail);
}); });
describe('for a group badge', () => { describe('for a group badge', () => {
...@@ -94,7 +97,7 @@ describe('BadgeListRow component', () => { ...@@ -94,7 +97,7 @@ describe('BadgeListRow component', () => {
}); });
it('renders the badge kind', () => { it('renders the badge kind', () => {
expect(vm.$el).toContainText('Group Badge'); expect(vm.$el.innerText).toMatch('Group Badge');
}); });
it('hides edit and delete buttons', () => { it('hides edit and delete buttons', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants'; import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants';
import store from '~/badges/store'; import store from '~/badges/store';
import BadgeList from '~/badges/components/badge_list.vue'; import BadgeList from '~/badges/components/badge_list.vue';
...@@ -22,6 +22,10 @@ describe('BadgeList component', () => { ...@@ -22,6 +22,10 @@ describe('BadgeList component', () => {
kind: PROJECT_BADGE, kind: PROJECT_BADGE,
isLoading: false, isLoading: false,
}); });
// Can be removed once GlLoadingIcon no longer throws a warning
jest.spyOn(global.console, 'warn').mockImplementation(() => jest.fn());
vm = mountComponentWithStore(Component, { vm = mountComponentWithStore(Component, {
el: '#dummy-element', el: '#dummy-element',
store, store,
...@@ -49,7 +53,7 @@ describe('BadgeList component', () => { ...@@ -49,7 +53,7 @@ describe('BadgeList component', () => {
Vue.nextTick() Vue.nextTick()
.then(() => { .then(() => {
expect(vm.$el).toContainText('This project has no badges'); expect(vm.$el.innerText).toMatch('This project has no badges');
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
...@@ -82,7 +86,7 @@ describe('BadgeList component', () => { ...@@ -82,7 +86,7 @@ describe('BadgeList component', () => {
Vue.nextTick() Vue.nextTick()
.then(() => { .then(() => {
expect(vm.$el).toContainText('This group has no badges'); expect(vm.$el.innerText).toMatch('This group has no badges');
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
......
import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import store from '~/badges/store'; import store from '~/badges/store';
import BadgeSettings from '~/badges/components/badge_settings.vue'; import BadgeSettings from '~/badges/components/badge_settings.vue';
import { createDummyBadge } from '../dummy_badge'; import { createDummyBadge } from '../dummy_badge';
...@@ -19,6 +18,10 @@ describe('BadgeSettings component', () => { ...@@ -19,6 +18,10 @@ describe('BadgeSettings component', () => {
data-target="#delete-badge-modal" data-target="#delete-badge-modal"
>Show modal</button> >Show modal</button>
`); `);
// Can be removed once GlLoadingIcon no longer throws a warning
jest.spyOn(global.console, 'warn').mockImplementation(() => jest.fn());
vm = mountComponentWithStore(Component, { vm = mountComponentWithStore(Component, {
el: '#dummy-element', el: '#dummy-element',
store, store,
...@@ -35,20 +38,16 @@ describe('BadgeSettings component', () => { ...@@ -35,20 +38,16 @@ describe('BadgeSettings component', () => {
const modal = vm.$el.querySelector('#delete-badge-modal'); const modal = vm.$el.querySelector('#delete-badge-modal');
const button = document.getElementById('dummy-modal-button'); const button = document.getElementById('dummy-modal-button');
$(modal).on('shown.bs.modal', () => { button.click();
expect(modal).toContainText('Delete badge?');
const badgeElement = modal.querySelector('img.project-badge');
expect(badgeElement).not.toBe(null);
expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl);
done();
});
Vue.nextTick() Vue.nextTick()
.then(() => { .then(() => {
button.click(); expect(modal.innerText).toMatch('Delete badge?');
const badgeElement = modal.querySelector('img.project-badge');
expect(badgeElement).not.toBe(null);
expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl);
}) })
.then(done)
.catch(done.fail); .catch(done.fail);
}); });
...@@ -67,7 +66,7 @@ describe('BadgeSettings component', () => { ...@@ -67,7 +66,7 @@ describe('BadgeSettings component', () => {
expect(badgeListElement).not.toBe(null); expect(badgeListElement).not.toBe(null);
expect(badgeListElement).toBeVisible(); expect(badgeListElement).toBeVisible();
expect(badgeListElement).toContainText('Your badges'); expect(badgeListElement.innerText).toMatch('Your badges');
}); });
describe('when editing', () => { describe('when editing', () => {
...@@ -103,7 +102,7 @@ describe('BadgeSettings component', () => { ...@@ -103,7 +102,7 @@ describe('BadgeSettings component', () => {
describe('methods', () => { describe('methods', () => {
describe('onSubmitModal', () => { describe('onSubmitModal', () => {
it('triggers ', () => { it('triggers ', () => {
spyOn(vm, 'deleteBadge').and.callFake(() => Promise.resolve()); jest.spyOn(vm, 'deleteBadge').mockImplementation(() => Promise.resolve());
const modal = vm.$el.querySelector('#delete-badge-modal'); const modal = vm.$el.querySelector('#delete-badge-modal');
const deleteButton = modal.querySelector('.btn-danger'); const deleteButton = modal.querySelector('.btn-danger');
......
import Vue from 'vue'; import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import { DUMMY_IMAGE_URL, TEST_HOST } from 'spec/test_constants'; import { DUMMY_IMAGE_URL, TEST_HOST } from 'spec/test_constants';
import Badge from '~/badges/components/badge.vue'; import Badge from '~/badges/components/badge.vue';
...@@ -23,9 +23,11 @@ describe('Badge component', () => { ...@@ -23,9 +23,11 @@ describe('Badge component', () => {
const createComponent = (props, el = null) => { const createComponent = (props, el = null) => {
vm = mountComponent(Component, props, el); vm = mountComponent(Component, props, el);
const { badgeImage } = findElements(); const { badgeImage } = findElements();
return new Promise(resolve => badgeImage.addEventListener('load', resolve)).then(() => return new Promise(resolve => {
Vue.nextTick(), badgeImage.addEventListener('load', resolve);
); // Manually dispatch load event as it is not triggered
badgeImage.dispatchEvent(new Event('load'));
}).then(() => Vue.nextTick());
}; };
afterEach(() => { afterEach(() => {
...@@ -111,7 +113,7 @@ describe('Badge component', () => { ...@@ -111,7 +113,7 @@ describe('Badge component', () => {
expect(badgeImage).toBeVisible(); expect(badgeImage).toBeVisible();
expect(loadingIcon).toBeHidden(); expect(loadingIcon).toBeHidden();
expect(reloadButton).toBeHidden(); expect(reloadButton).toBeHidden();
expect(vm.$el.innerText).toBe(''); expect(vm.$el.querySelector('.btn-group')).toBeHidden();
}); });
it('shows a loading icon when loading', done => { it('shows a loading icon when loading', done => {
...@@ -124,7 +126,7 @@ describe('Badge component', () => { ...@@ -124,7 +126,7 @@ describe('Badge component', () => {
expect(badgeImage).toBeHidden(); expect(badgeImage).toBeHidden();
expect(loadingIcon).toBeVisible(); expect(loadingIcon).toBeVisible();
expect(reloadButton).toBeHidden(); expect(reloadButton).toBeHidden();
expect(vm.$el.innerText).toBe(''); expect(vm.$el.querySelector('.btn-group')).toBeHidden();
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
......
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