Commit 61a23c2e authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'migrate_ee_spec_javascripts_vue_mr_widget_components_approvals_spec' into 'master'

Migrate ee vue_mr_widget approvals_spec to Jest

Closes #194309

See merge request gitlab-org/gitlab!30451
parents 0f41dcfc 88a4e8a5
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import Approvals from 'ee/vue_merge_request_widget/components/approvals/approvals.vue'; import Approvals from 'ee/vue_merge_request_widget/components/approvals/approvals.vue';
import ApprovalsSummary from 'ee/vue_merge_request_widget/components/approvals/approvals_summary.vue'; import ApprovalsSummary from 'ee/vue_merge_request_widget/components/approvals/approvals_summary.vue';
import ApprovalsSummaryOptional from 'ee/vue_merge_request_widget/components/approvals/approvals_summary_optional.vue'; import ApprovalsSummaryOptional from 'ee/vue_merge_request_widget/components/approvals/approvals_summary_optional.vue';
import ApprovalsFooter from 'ee/vue_merge_request_widget/components/approvals/approvals_footer.vue'; import ApprovalsFooter from 'ee/vue_merge_request_widget/components/approvals/approvals_footer.vue';
import ApprovalsAuth from 'ee/vue_merge_request_widget/components/approvals/approvals_auth.vue'; import ApprovalsAuth from 'ee/vue_merge_request_widget/components/approvals/approvals_auth.vue';
import createFlash from '~/flash';
import { import {
FETCH_LOADING, FETCH_LOADING,
...@@ -14,7 +15,6 @@ import { ...@@ -14,7 +15,6 @@ import {
} from 'ee/vue_merge_request_widget/components/approvals/messages'; } from 'ee/vue_merge_request_widget/components/approvals/messages';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
const localVue = createLocalVue();
const TEST_HELP_PATH = 'help/path'; const TEST_HELP_PATH = 'help/path';
const TEST_PASSWORD = 'password'; const TEST_PASSWORD = 'password';
const testApprovedBy = () => [1, 7, 10].map(id => ({ id })); const testApprovedBy = () => [1, 7, 10].map(id => ({ id }));
...@@ -30,28 +30,20 @@ const testApprovals = () => ({ ...@@ -30,28 +30,20 @@ const testApprovals = () => ({
}); });
const testApprovalRulesResponse = () => ({ rules: [{ id: 2 }] }); const testApprovalRulesResponse = () => ({ rules: [{ id: 2 }] });
// For some reason, the `localVue.nextTick` needs to be deferred jest.mock('~/flash');
// or the timing doesn't work.
const tick = () => Promise.resolve().then(localVue.nextTick);
const waitForTick = done =>
tick()
.then(done)
.catch(done.fail);
describe('EE MRWidget approvals', () => { describe('EE MRWidget approvals', () => {
let wrapper; let wrapper;
let service; let service;
let mr; let mr;
let createFlash;
const createComponent = (props = {}) => { const createComponent = (props = {}) => {
wrapper = shallowMount(localVue.extend(Approvals), { wrapper = shallowMount(Approvals, {
propsData: { propsData: {
mr, mr,
service, service,
...props, ...props,
}, },
localVue,
}); });
}; };
...@@ -72,24 +64,29 @@ describe('EE MRWidget approvals', () => { ...@@ -72,24 +64,29 @@ describe('EE MRWidget approvals', () => {
const findFooter = () => wrapper.find(ApprovalsFooter); const findFooter = () => wrapper.find(ApprovalsFooter);
beforeEach(() => { beforeEach(() => {
service = jasmine.createSpyObj('MRWidgetService', { service = {
fetchApprovals: Promise.resolve(testApprovals()), ...{
fetchApprovalSettings: Promise.resolve(testApprovalRulesResponse()), fetchApprovals: jest.fn().mockResolvedValue(testApprovals()),
approveMergeRequest: Promise.resolve(testApprovals()), fetchApprovalSettings: jest.fn().mockResolvedValue(testApprovalRulesResponse()),
unapproveMergeRequest: Promise.resolve(testApprovals()), approveMergeRequest: jest.fn().mockResolvedValue(testApprovals()),
approveMergeRequestWithAuth: Promise.resolve(testApprovals()), unapproveMergeRequest: jest.fn().mockResolvedValue(testApprovals()),
}); approveMergeRequestWithAuth: jest.fn().mockResolvedValue(testApprovals()),
},
};
mr = { mr = {
...jasmine.createSpyObj('Store', ['setApprovals', 'setApprovalRules']), ...{
setApprovals: jest.fn(),
setApprovalRules: jest.fn(),
},
approvalsHelpPath: TEST_HELP_PATH, approvalsHelpPath: TEST_HELP_PATH,
approvals: testApprovals(), approvals: testApprovals(),
approvalRules: [], approvalRules: [],
isOpen: true, isOpen: true,
state: 'open', state: 'open',
}; };
createFlash = spyOnDependency(Approvals, 'createFlash');
spyOn(eventHub, '$emit'); jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
...@@ -99,11 +96,16 @@ describe('EE MRWidget approvals', () => { ...@@ -99,11 +96,16 @@ describe('EE MRWidget approvals', () => {
describe('when created', () => { describe('when created', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(service, 'fetchApprovals').mockResolvedValue(testApprovals());
createComponent(); createComponent();
}); });
it('shows loading message', () => { it('shows loading message', () => {
expect(wrapper.text()).toContain(FETCH_LOADING); wrapper.setData({ fetchingApprovals: true });
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.text()).toContain(FETCH_LOADING);
});
}); });
it('fetches approvals', () => { it('fetches approvals', () => {
...@@ -112,10 +114,11 @@ describe('EE MRWidget approvals', () => { ...@@ -112,10 +114,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('when fetch approvals success', () => { describe('when fetch approvals success', () => {
beforeEach(done => { beforeEach(() => {
service.fetchApprovals.and.returnValue(Promise.resolve()); jest.spyOn(service, 'fetchApprovals').mockResolvedValue();
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('hides loading message', () => { it('hides loading message', () => {
...@@ -125,10 +128,11 @@ describe('EE MRWidget approvals', () => { ...@@ -125,10 +128,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('when fetch approvals error', () => { describe('when fetch approvals error', () => {
beforeEach(done => { beforeEach(() => {
service.fetchApprovals.and.returnValue(Promise.reject()); jest.spyOn(service, 'fetchApprovals').mockRejectedValue();
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('still shows loading message', () => { it('still shows loading message', () => {
...@@ -141,14 +145,19 @@ describe('EE MRWidget approvals', () => { ...@@ -141,14 +145,19 @@ describe('EE MRWidget approvals', () => {
}); });
describe('action button', () => { describe('action button', () => {
beforeEach(() => {
jest.spyOn(service, 'fetchApprovals').mockResolvedValue(testApprovals());
});
describe('when mr is closed', () => { describe('when mr is closed', () => {
beforeEach(done => { beforeEach(() => {
mr.isOpen = false; mr.isOpen = false;
mr.approvals.user_has_approved = false; mr.approvals.user_has_approved = false;
mr.approvals.user_can_approve = true; mr.approvals.user_can_approve = true;
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('action is not rendered', () => { it('action is not rendered', () => {
...@@ -157,12 +166,13 @@ describe('EE MRWidget approvals', () => { ...@@ -157,12 +166,13 @@ describe('EE MRWidget approvals', () => {
}); });
describe('when user cannot approve', () => { describe('when user cannot approve', () => {
beforeEach(done => { beforeEach(() => {
mr.approvals.user_has_approved = false; mr.approvals.user_has_approved = false;
mr.approvals.user_can_approve = false; mr.approvals.user_can_approve = false;
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('action is not rendered', () => { it('action is not rendered', () => {
...@@ -177,9 +187,10 @@ describe('EE MRWidget approvals', () => { ...@@ -177,9 +187,10 @@ describe('EE MRWidget approvals', () => {
}); });
describe('and MR is unapproved', () => { describe('and MR is unapproved', () => {
beforeEach(done => { beforeEach(() => {
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('approve action is rendered', () => { it('approve action is rendered', () => {
...@@ -197,10 +208,11 @@ describe('EE MRWidget approvals', () => { ...@@ -197,10 +208,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('with no approvers', () => { describe('with no approvers', () => {
beforeEach(done => { beforeEach(() => {
mr.approvals.approved_by = []; mr.approvals.approved_by = [];
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('approve action (with inverted style) is rendered', () => { it('approve action (with inverted style) is rendered', () => {
...@@ -213,10 +225,11 @@ describe('EE MRWidget approvals', () => { ...@@ -213,10 +225,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('with approvers', () => { describe('with approvers', () => {
beforeEach(done => { beforeEach(() => {
mr.approvals.approved_by = [{ user: { id: 7 } }]; mr.approvals.approved_by = [{ user: { id: 7 } }];
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('approve additionally action is rendered', () => { it('approve additionally action is rendered', () => {
...@@ -230,31 +243,30 @@ describe('EE MRWidget approvals', () => { ...@@ -230,31 +243,30 @@ describe('EE MRWidget approvals', () => {
}); });
describe('when approve action is clicked', () => { describe('when approve action is clicked', () => {
beforeEach(done => { beforeEach(() => {
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('shows loading icon', done => { it('shows loading icon', () => {
service.approveMergeRequest.and.callFake(() => new Promise(() => {})); jest.spyOn(service, 'approveMergeRequest').mockReturnValue(new Promise(() => {}));
const action = findAction(); const action = findAction();
expect(action.props('loading')).toBe(false); expect(action.props('loading')).toBe(false);
action.vm.$emit('click'); action.vm.$emit('click');
tick() return wrapper.vm.$nextTick().then(() => {
.then(() => { expect(action.props('loading')).toBe(true);
expect(action.props('loading')).toBe(true); });
})
.then(done)
.catch(done.fail);
}); });
describe('and after loading', () => { describe('and after loading', () => {
beforeEach(done => { beforeEach(() => {
findAction().vm.$emit('click'); findAction().vm.$emit('click');
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('calls service approve', () => { it('calls service approve', () => {
...@@ -275,10 +287,11 @@ describe('EE MRWidget approvals', () => { ...@@ -275,10 +287,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('and error', () => { describe('and error', () => {
beforeEach(done => { beforeEach(() => {
service.approveMergeRequest.and.returnValue(Promise.reject()); jest.spyOn(service, 'approveMergeRequest').mockRejectedValue();
findAction().vm.$emit('click'); findAction().vm.$emit('click');
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('flashes error message', () => { it('flashes error message', () => {
...@@ -288,59 +301,54 @@ describe('EE MRWidget approvals', () => { ...@@ -288,59 +301,54 @@ describe('EE MRWidget approvals', () => {
}); });
describe('when project requires password to approve', () => { describe('when project requires password to approve', () => {
beforeEach(done => { beforeEach(() => {
mr.approvals.require_password_to_approve = true; mr.approvals.require_password_to_approve = true;
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
describe('when approve is clicked', () => { describe('when approve is clicked', () => {
beforeEach(done => { beforeEach(() => {
findAction().vm.$emit('click'); findAction().vm.$emit('click');
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
describe('when emits approve', () => { describe('when emits approve', () => {
let authReject; const findApprovalsAuth = () => wrapper.find(ApprovalsAuth);
beforeEach(done => { beforeEach(() => {
service.approveMergeRequestWithAuth.and.returnValue( jest.spyOn(service, 'approveMergeRequestWithAuth').mockRejectedValue();
new Promise((resolve, reject) => { jest.spyOn(service, 'approveMergeRequest').mockReturnValue(new Promise(() => {}));
authReject = reject;
}), findApprovalsAuth().vm.$emit('approve', TEST_PASSWORD);
);
wrapper.find(ApprovalsAuth).vm.$emit('approve', TEST_PASSWORD); return wrapper.vm.$nextTick();
waitForTick(done);
}); });
it('calls service when emits approve', () => { it('calls service when emits approve', () => {
expect(service.approveMergeRequestWithAuth).toHaveBeenCalledWith(TEST_PASSWORD); expect(service.approveMergeRequestWithAuth).toHaveBeenCalledWith(TEST_PASSWORD);
}); });
it('sets isLoading on auth', () => { it('sets isApproving', () => {
expect(wrapper.find(ApprovalsAuth).props('isApproving')).toBe(true); wrapper.setData({ isApproving: true });
return wrapper.vm.$nextTick().then(() => {
expect(findApprovalsAuth().props('isApproving')).toBe(true);
});
}); });
it('sets hasError when auth fails', done => { it('sets hasError when auth fails', () => {
authReject({ response: { status: 401 } }); wrapper.setData({ hasApprovalAuthError: true });
tick() return wrapper.vm.$nextTick().then(() => {
.then(() => { expect(findApprovalsAuth().props('hasError')).toBe(true);
expect(wrapper.find(ApprovalsAuth).props('hasError')).toBe(true); });
})
.then(done)
.catch(done.fail);
}); });
it('shows flash if general error', done => { it('shows flash if general error', () => {
authReject('something really bad!'); expect(createFlash).toHaveBeenCalledWith(APPROVE_ERROR);
tick()
.then(() => {
expect(createFlash).toHaveBeenCalledWith(APPROVE_ERROR);
})
.then(done)
.catch(done.fail);
}); });
}); });
}); });
...@@ -348,12 +356,13 @@ describe('EE MRWidget approvals', () => { ...@@ -348,12 +356,13 @@ describe('EE MRWidget approvals', () => {
}); });
describe('when user has approved', () => { describe('when user has approved', () => {
beforeEach(done => { beforeEach(() => {
mr.approvals.user_has_approved = true; mr.approvals.user_has_approved = true;
mr.approvals.user_can_approve = false; mr.approvals.user_can_approve = false;
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('revoke action is rendered', () => { it('revoke action is rendered', () => {
...@@ -366,9 +375,10 @@ describe('EE MRWidget approvals', () => { ...@@ -366,9 +375,10 @@ describe('EE MRWidget approvals', () => {
describe('when revoke action is clicked', () => { describe('when revoke action is clicked', () => {
describe('and successful', () => { describe('and successful', () => {
beforeEach(done => { beforeEach(() => {
findAction().vm.$emit('click'); findAction().vm.$emit('click');
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('calls service unapprove', () => { it('calls service unapprove', () => {
...@@ -389,10 +399,11 @@ describe('EE MRWidget approvals', () => { ...@@ -389,10 +399,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('and error', () => { describe('and error', () => {
beforeEach(done => { beforeEach(() => {
service.unapproveMergeRequest.and.returnValue(Promise.reject()); jest.spyOn(service, 'unapproveMergeRequest').mockRejectedValue();
findAction().vm.$emit('click'); findAction().vm.$emit('click');
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('flashes error message', () => { it('flashes error message', () => {
...@@ -406,17 +417,19 @@ describe('EE MRWidget approvals', () => { ...@@ -406,17 +417,19 @@ describe('EE MRWidget approvals', () => {
describe('approvals optional summary', () => { describe('approvals optional summary', () => {
describe('when no approvals required and no approvers', () => { describe('when no approvals required and no approvers', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(service, 'fetchApprovals').mockResolvedValue(testApprovals());
mr.approvals.approved_by = []; mr.approvals.approved_by = [];
mr.approvals.approvals_required = 0; mr.approvals.approvals_required = 0;
mr.approvals.user_has_approved = false; mr.approvals.user_has_approved = false;
}); });
describe('and can approve', () => { describe('and can approve', () => {
beforeEach(done => { beforeEach(() => {
mr.approvals.user_can_approve = true; mr.approvals.user_can_approve = true;
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('is shown', () => { it('is shown', () => {
...@@ -429,11 +442,12 @@ describe('EE MRWidget approvals', () => { ...@@ -429,11 +442,12 @@ describe('EE MRWidget approvals', () => {
}); });
describe('and cannot approve', () => { describe('and cannot approve', () => {
beforeEach(done => { beforeEach(() => {
mr.approvals.user_can_approve = false; mr.approvals.user_can_approve = false;
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('is shown', () => { it('is shown', () => {
...@@ -448,9 +462,11 @@ describe('EE MRWidget approvals', () => { ...@@ -448,9 +462,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('approvals summary', () => { describe('approvals summary', () => {
beforeEach(done => { beforeEach(() => {
jest.spyOn(service, 'fetchApprovals').mockResolvedValue(testApprovals());
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('is rendered with props', () => { it('is rendered with props', () => {
...@@ -459,22 +475,22 @@ describe('EE MRWidget approvals', () => { ...@@ -459,22 +475,22 @@ describe('EE MRWidget approvals', () => {
expect(findOptionalSummary().exists()).toBe(false); expect(findOptionalSummary().exists()).toBe(false);
expect(summary.exists()).toBe(true); expect(summary.exists()).toBe(true);
expect(summary.props()).toEqual( expect(summary.props()).toMatchObject({
jasmine.objectContaining({ approvalsLeft: expected.approvals_left,
approvalsLeft: expected.approvals_left, rulesLeft: expected.approval_rules_left,
rulesLeft: expected.approval_rules_left, approvers: testApprovedBy(),
approvers: testApprovedBy(), });
}),
);
}); });
}); });
describe('footer', () => { describe('footer', () => {
let footer; let footer;
beforeEach(done => { beforeEach(() => {
jest.spyOn(service, 'fetchApprovals').mockResolvedValue(testApprovals());
createComponent(); createComponent();
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
beforeEach(() => { beforeEach(() => {
...@@ -483,22 +499,21 @@ describe('EE MRWidget approvals', () => { ...@@ -483,22 +499,21 @@ describe('EE MRWidget approvals', () => {
it('is rendered with props', () => { it('is rendered with props', () => {
expect(footer.exists()).toBe(true); expect(footer.exists()).toBe(true);
expect(footer.props()).toEqual( expect(footer.props()).toMatchObject({
jasmine.objectContaining({ value: false,
value: false, suggestedApprovers: mr.approvals.suggested_approvers,
suggestedApprovers: mr.approvals.suggested_approvers, approvalRules: mr.approvalRules,
approvalRules: mr.approvalRules, isLoadingRules: false,
isLoadingRules: false, });
}),
);
}); });
describe('when opened', () => { describe('when opened', () => {
describe('and loading', () => { describe('and loading', () => {
beforeEach(done => { beforeEach(() => {
service.fetchApprovalSettings.and.callFake(() => new Promise(() => {})); jest.spyOn(service, 'fetchApprovalSettings').mockReturnValue(new Promise(() => {}));
footer.vm.$emit('input', true); footer.vm.$emit('input', true);
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('calls service fetch approval rules', () => { it('calls service fetch approval rules', () => {
...@@ -512,9 +527,10 @@ describe('EE MRWidget approvals', () => { ...@@ -512,9 +527,10 @@ describe('EE MRWidget approvals', () => {
}); });
describe('and finished loading', () => { describe('and finished loading', () => {
beforeEach(done => { beforeEach(() => {
footer.vm.$emit('input', true); footer.vm.$emit('input', true);
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('sets approval rules', () => { it('sets approval rules', () => {
...@@ -526,10 +542,11 @@ describe('EE MRWidget approvals', () => { ...@@ -526,10 +542,11 @@ describe('EE MRWidget approvals', () => {
}); });
describe('and closed', () => { describe('and closed', () => {
beforeEach(done => { beforeEach(() => {
service.fetchApprovalSettings.calls.reset(); service.fetchApprovalSettings.mockClear();
footer.vm.$emit('input', false); footer.vm.$emit('input', false);
waitForTick(done);
return wrapper.vm.$nextTick();
}); });
it('does not call service fetch approval rules', () => { it('does not call service fetch approval rules', () => {
......
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