From 9becb832b0fa3a8c38630c8fe516238741893050 Mon Sep 17 00:00:00 2001 From: Paul Slaughter Date: Sat, 5 Jan 2019 00:54:58 -0600 Subject: [PATCH 1/2] FE store for MR approvals settings **Note:** - This contains the service stub which is removed in a later commit - Adds modal modules which will ref components in a later commit --- .../assets/javascripts/approvals/mappers.js | 19 +++ .../javascripts/approvals/stores/actions.js | 43 ++++- .../javascripts/approvals/stores/index.js | 5 + .../approvals/stores/actions_spec.js | 149 +++++++++++++++++- locale/gitlab.pot | 6 + 5 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 ee/app/assets/javascripts/approvals/mappers.js diff --git a/ee/app/assets/javascripts/approvals/mappers.js b/ee/app/assets/javascripts/approvals/mappers.js new file mode 100644 index 00000000000000..4d67822cf7bbc8 --- /dev/null +++ b/ee/app/assets/javascripts/approvals/mappers.js @@ -0,0 +1,19 @@ +export const mapApprovalRuleRequest = req => ({ + name: req.name, + approvals_required: req.approvalsRequired, + users: req.users, + groups: req.groups, +}); + +export const mapApprovalRuleResponse = res => ({ + id: res.id, + name: res.name, + approvalsRequired: res.approvals_required, + approvers: res.approvers, + users: res.users, + groups: res.groups, +}); + +export const mapApprovalRulesResponse = req => ({ + rules: req.rules.map(mapApprovalRuleResponse), +}); diff --git a/ee/app/assets/javascripts/approvals/stores/actions.js b/ee/app/assets/javascripts/approvals/stores/actions.js index 1b121b508783b0..39a6385c041dbb 100644 --- a/ee/app/assets/javascripts/approvals/stores/actions.js +++ b/ee/app/assets/javascripts/approvals/stores/actions.js @@ -2,6 +2,7 @@ import createFlash from '~/flash'; import { __ } from '~/locale'; import * as types from './mutation_types'; import service from '../services/approvals_service_stub'; +import { mapApprovalRuleRequest, mapApprovalRulesResponse } from '../mappers'; export const setSettings = ({ commit }, settings) => { commit(types.SET_SETTINGS, settings); @@ -22,13 +23,49 @@ export const receiveRulesError = () => { export const fetchRules = ({ state, dispatch }) => { if (state.isLoading) { - return; + return Promise.resolve(); } dispatch('requestRules'); - service + return service .getProjectApprovalRules() - .then(response => dispatch('receiveRulesSuccess', response.data)) + .then(response => dispatch('receiveRulesSuccess', mapApprovalRulesResponse(response.data))) .catch(() => dispatch('receiveRulesError')); }; + +export const postRuleSuccess = ({ dispatch }) => { + dispatch('createModal/close'); + dispatch('fetchRules'); +}; + +export const postRuleError = () => { + createFlash(__('An error occurred while updating approvers')); +}; + +export const postRule = ({ dispatch }, rule) => + service + .postProjectApprovalRule(mapApprovalRuleRequest(rule)) + .then(() => dispatch('postRuleSuccess')) + .catch(() => dispatch('postRuleError')); + +export const putRule = ({ dispatch }, { id, ...newRule }) => + service + .putProjectApprovalRule(id, mapApprovalRuleRequest(newRule)) + .then(() => dispatch('postRuleSuccess')) + .catch(() => dispatch('postRuleError')); + +export const deleteRuleSuccess = ({ dispatch }) => { + dispatch('deleteModal/close'); + dispatch('fetchRules'); +}; + +export const deleteRuleError = () => { + createFlash(__('An error occurred while deleting the approvers group')); +}; + +export const deleteRule = ({ dispatch }, id) => + service + .deleteProjectApprovalRule(id) + .then(() => dispatch('deleteRuleSuccess')) + .catch(() => dispatch('deleteRuleError')); diff --git a/ee/app/assets/javascripts/approvals/stores/index.js b/ee/app/assets/javascripts/approvals/stores/index.js index 64c78d2cb4ab7d..8d34f826efc3f7 100644 --- a/ee/app/assets/javascripts/approvals/stores/index.js +++ b/ee/app/assets/javascripts/approvals/stores/index.js @@ -1,4 +1,5 @@ import Vuex from 'vuex'; +import modalModule from '~/vuex_shared/modules/modal'; import state from './state'; import mutations from './mutations'; import * as actions from './actions'; @@ -8,4 +9,8 @@ export default () => state: state(), mutations, actions, + modules: { + createModal: modalModule(), + deleteModal: modalModule(), + }, }); diff --git a/ee/spec/javascripts/approvals/stores/actions_spec.js b/ee/spec/javascripts/approvals/stores/actions_spec.js index 05ee18d8d75794..08348ca7459aea 100644 --- a/ee/spec/javascripts/approvals/stores/actions_spec.js +++ b/ee/spec/javascripts/approvals/stores/actions_spec.js @@ -2,6 +2,23 @@ import testAction from 'spec/helpers/vuex_action_helper'; import * as types from 'ee/approvals/stores/mutation_types'; import actionsModule, * as actions from 'ee/approvals/stores/actions'; import service from 'ee/approvals/services/approvals_service_stub'; +import { mapApprovalRuleRequest, mapApprovalRulesResponse } from 'ee/approvals/mappers'; + +const TEST_RULE_ID = 7; +const TEST_RULE_REQUEST = { + name: 'Lorem', + approvalsRequired: 1, + groups: [7], + users: [8, 9], +}; +const TEST_RULE_RESPONSE = { + id: 7, + name: 'Ipsum', + approvals_required: 2, + approvers: [{ id: 7 }, { id: 8 }, { id: 9 }], + groups: [{ id: 4 }], + users: [{ id: 7 }, { id: 8 }], +}; describe('EE approvals store actions', () => { let flashSpy; @@ -9,6 +26,9 @@ describe('EE approvals store actions', () => { beforeEach(() => { flashSpy = spyOnDependency(actionsModule, 'createFlash'); spyOn(service, 'getProjectApprovalRules'); + spyOn(service, 'postProjectApprovalRule'); + spyOn(service, 'putProjectApprovalRule'); + spyOn(service, 'deleteProjectApprovalRule'); }); describe('setSettings', () => { @@ -72,7 +92,7 @@ describe('EE approvals store actions', () => { it('dispatches request/receive', done => { const response = { - data: { rules: [] }, + data: { rules: [TEST_RULE_RESPONSE] }, }; service.getProjectApprovalRules.and.returnValue(Promise.resolve(response)); @@ -81,7 +101,10 @@ describe('EE approvals store actions', () => { null, {}, [], - [{ type: 'requestRules' }, { type: 'receiveRulesSuccess', payload: response.data }], + [ + { type: 'requestRules' }, + { type: 'receiveRulesSuccess', payload: mapApprovalRulesResponse(response.data) }, + ], done, ); }); @@ -99,4 +122,126 @@ describe('EE approvals store actions', () => { ); }); }); + + describe('postRuleSuccess', () => { + it('closes modal and fetches', done => { + testAction( + actions.postRuleSuccess, + null, + {}, + [], + [{ type: 'createModal/close' }, { type: 'fetchRules' }], + done, + ); + }); + }); + + describe('postRuleError', () => { + it('creates a flash', () => { + expect(flashSpy).not.toHaveBeenCalled(); + + actions.postRuleError(); + + expect(flashSpy.calls.allArgs()).toEqual([[jasmine.stringMatching('error occurred')]]); + }); + }); + + describe('postRule', () => { + it('dispatches success on success', done => { + service.postProjectApprovalRule.and.callFake(data => { + expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); + return Promise.resolve(); + }); + + testAction(actions.postRule, TEST_RULE_REQUEST, {}, [], [{ type: 'postRuleSuccess' }], done); + }); + + it('dispatches error on error', done => { + service.postProjectApprovalRule.and.callFake(data => { + expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); + return Promise.reject(); + }); + + testAction(actions.postRule, TEST_RULE_REQUEST, {}, [], [{ type: 'postRuleError' }], done); + }); + }); + + describe('putRule', () => { + it('dispatches success on success', done => { + service.putProjectApprovalRule.and.callFake((id, data) => { + expect(id).toBe(TEST_RULE_ID); + expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); + return Promise.resolve(); + }); + + testAction( + actions.putRule, + { id: TEST_RULE_ID, ...TEST_RULE_REQUEST }, + {}, + [], + [{ type: 'postRuleSuccess' }], + done, + ); + }); + + it('dispatches error on error', done => { + service.putProjectApprovalRule.and.callFake((id, data) => { + expect(id).toBe(TEST_RULE_ID); + expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); + return Promise.reject(); + }); + + testAction( + actions.putRule, + { id: TEST_RULE_ID, ...TEST_RULE_REQUEST }, + {}, + [], + [{ type: 'postRuleError' }], + done, + ); + }); + }); + + describe('deleteRuleSuccess', () => { + it('closes modal and fetches', done => { + testAction( + actions.deleteRuleSuccess, + null, + {}, + [], + [{ type: 'deleteModal/close' }, { type: 'fetchRules' }], + done, + ); + }); + }); + + describe('deleteRuleError', () => { + it('creates a flash', () => { + expect(flashSpy).not.toHaveBeenCalled(); + + actions.deleteRuleError(); + + expect(flashSpy.calls.allArgs()).toEqual([[jasmine.stringMatching('error occurred')]]); + }); + }); + + describe('deleteRule', () => { + it('dispatches success on success', done => { + service.deleteProjectApprovalRule.and.callFake(id => { + expect(id).toBe(TEST_RULE_ID); + return Promise.resolve(); + }); + + testAction(actions.deleteRule, TEST_RULE_ID, {}, [], [{ type: 'deleteRuleSuccess' }], done); + }); + + it('dispatches error on error', done => { + service.deleteProjectApprovalRule.and.callFake(id => { + expect(id).toBe(TEST_RULE_ID); + return Promise.reject(); + }); + + testAction(actions.deleteRule, TEST_RULE_ID, {}, [], [{ type: 'deleteRuleError' }], done); + }); + }); }); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7c97844e9024d5..7067f7a24a61fe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -686,6 +686,9 @@ msgstr "" msgid "An error occurred while adding approver" msgstr "" +msgid "An error occurred while deleting the approvers group" +msgstr "" + msgid "An error occurred while deleting the comment" msgstr "" @@ -779,6 +782,9 @@ msgstr "" msgid "An error occurred while unsubscribing to notifications." msgstr "" +msgid "An error occurred while updating approvers" +msgstr "" + msgid "An error occurred while updating the comment" msgstr "" -- GitLab From fdbff41d62650f84d4982b02484dc8964b1ebe30 Mon Sep 17 00:00:00 2001 From: Paul Slaughter Date: Sun, 30 Dec 2018 16:05:34 -0600 Subject: [PATCH 2/2] Integrate approval rules settings FE with BE - Adds endpoints to API - Removes service stub --- ee/app/assets/javascripts/api.js | 41 ++++++ .../services/approvals_service_stub.js | 20 --- .../javascripts/approvals/stores/actions.js | 31 +++-- ee/spec/javascripts/api_spec.js | 90 +++++++++++++ .../approvals/stores/actions_spec.js | 120 +++++++++++------- 5 files changed, 227 insertions(+), 75 deletions(-) create mode 100644 ee/app/assets/javascripts/api.js delete mode 100644 ee/app/assets/javascripts/approvals/services/approvals_service_stub.js create mode 100644 ee/spec/javascripts/api_spec.js diff --git a/ee/app/assets/javascripts/api.js b/ee/app/assets/javascripts/api.js new file mode 100644 index 00000000000000..aebea5a7f4bf09 --- /dev/null +++ b/ee/app/assets/javascripts/api.js @@ -0,0 +1,41 @@ +import CEApi from '~/api'; +import axios from '~/lib/utils/axios_utils'; + +export default { + ...CEApi, + projectApprovalRulesPath: '/api/:version/projects/:id/approval_rules', + projectApprovalRulePath: '/api/:version/projects/:id/approval_rules/:ruleid', + getProjectApprovalRules(projectId) { + const url = this.buildUrl(this.projectApprovalRulesPath).replace( + ':id', + encodeURIComponent(projectId), + ); + + return axios.get(url); + }, + + postProjectApprovalRule(projectId, rule) { + const url = this.buildUrl(this.projectApprovalRulesPath).replace( + ':id', + encodeURIComponent(projectId), + ); + + return axios.post(url, rule); + }, + + putProjectApprovalRule(projectId, ruleId, rule) { + const url = this.buildUrl(this.projectApprovalRulePath) + .replace(':id', encodeURIComponent(projectId)) + .replace(':ruleid', encodeURIComponent(ruleId)); + + return axios.put(url, rule); + }, + + deleteProjectApprovalRule(projectId, ruleId) { + const url = this.buildUrl(this.projectApprovalRulePath) + .replace(':id', encodeURIComponent(projectId)) + .replace(':ruleid', encodeURIComponent(ruleId)); + + return axios.delete(url); + }, +}; diff --git a/ee/app/assets/javascripts/approvals/services/approvals_service_stub.js b/ee/app/assets/javascripts/approvals/services/approvals_service_stub.js deleted file mode 100644 index 4288f874520664..00000000000000 --- a/ee/app/assets/javascripts/approvals/services/approvals_service_stub.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This provides a stubbed API for approval rule requests. - * - * **PLEASE NOTE:** - * - This class will be removed when the BE is merged for https://gitlab.com/gitlab-org/gitlab-ee/issues/1979 - */ - -export function createApprovalsServiceStub() { - const projectApprovalRules = []; - - return { - getProjectApprovalRules() { - return Promise.resolve({ - data: { rules: projectApprovalRules }, - }); - }, - }; -} - -export default createApprovalsServiceStub(); diff --git a/ee/app/assets/javascripts/approvals/stores/actions.js b/ee/app/assets/javascripts/approvals/stores/actions.js index 39a6385c041dbb..6a133a851c7bc9 100644 --- a/ee/app/assets/javascripts/approvals/stores/actions.js +++ b/ee/app/assets/javascripts/approvals/stores/actions.js @@ -1,7 +1,7 @@ import createFlash from '~/flash'; import { __ } from '~/locale'; +import Api from 'ee/api'; import * as types from './mutation_types'; -import service from '../services/approvals_service_stub'; import { mapApprovalRuleRequest, mapApprovalRulesResponse } from '../mappers'; export const setSettings = ({ commit }, settings) => { @@ -26,10 +26,11 @@ export const fetchRules = ({ state, dispatch }) => { return Promise.resolve(); } + const { projectId } = state.settings; + dispatch('requestRules'); - return service - .getProjectApprovalRules() + return Api.getProjectApprovalRules(projectId) .then(response => dispatch('receiveRulesSuccess', mapApprovalRulesResponse(response.data))) .catch(() => dispatch('receiveRulesError')); }; @@ -43,17 +44,21 @@ export const postRuleError = () => { createFlash(__('An error occurred while updating approvers')); }; -export const postRule = ({ dispatch }, rule) => - service - .postProjectApprovalRule(mapApprovalRuleRequest(rule)) +export const postRule = ({ state, dispatch }, rule) => { + const { projectId } = state.settings; + + return Api.postProjectApprovalRule(projectId, mapApprovalRuleRequest(rule)) .then(() => dispatch('postRuleSuccess')) .catch(() => dispatch('postRuleError')); +}; + +export const putRule = ({ state, dispatch }, { id, ...newRule }) => { + const { projectId } = state.settings; -export const putRule = ({ dispatch }, { id, ...newRule }) => - service - .putProjectApprovalRule(id, mapApprovalRuleRequest(newRule)) + return Api.putProjectApprovalRule(projectId, id, mapApprovalRuleRequest(newRule)) .then(() => dispatch('postRuleSuccess')) .catch(() => dispatch('postRuleError')); +}; export const deleteRuleSuccess = ({ dispatch }) => { dispatch('deleteModal/close'); @@ -64,8 +69,10 @@ export const deleteRuleError = () => { createFlash(__('An error occurred while deleting the approvers group')); }; -export const deleteRule = ({ dispatch }, id) => - service - .deleteProjectApprovalRule(id) +export const deleteRule = ({ state, dispatch }, id) => { + const { projectId } = state.settings; + + return Api.deleteProjectApprovalRule(projectId, id) .then(() => dispatch('deleteRuleSuccess')) .catch(() => dispatch('deleteRuleError')); +}; diff --git a/ee/spec/javascripts/api_spec.js b/ee/spec/javascripts/api_spec.js new file mode 100644 index 00000000000000..a0674c2539157a --- /dev/null +++ b/ee/spec/javascripts/api_spec.js @@ -0,0 +1,90 @@ +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; +import Api from 'ee/api'; +import { TEST_HOST } from 'spec/test_constants'; + +const TEST_API_VERSION = 'v3000'; +const TEST_PROJECT_ID = 17; +const TEST_RULE_ID = 22; + +describe('EE Api', () => { + let originalGon; + let mock; + + beforeEach(() => { + mock = new MockAdapter(axios); + originalGon = window.gon; + window.gon = { + api_version: TEST_API_VERSION, + relative_url_root: TEST_HOST, + }; + }); + + afterEach(() => { + mock.restore(); + window.gon = originalGon; + }); + + describe('getProjectApprovalRules', () => { + it('gets with projectApprovalRulesPath', done => { + const expectedData = { rules: [] }; + const expectedUrl = `${TEST_HOST}${Api.projectApprovalRulesPath}` + .replace(':version', TEST_API_VERSION) + .replace(':id', TEST_PROJECT_ID); + + mock.onGet(expectedUrl).reply(200, expectedData); + Api.getProjectApprovalRules(TEST_PROJECT_ID) + .then(response => { + expect(response.data).toEqual(expectedData); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('postProjectApprovalRule', () => { + it('posts with projectApprovalRulesPath', done => { + const expectedUrl = `${TEST_HOST}${Api.projectApprovalRulesPath}` + .replace(':version', TEST_API_VERSION) + .replace(':id', TEST_PROJECT_ID); + + mock.onPost(expectedUrl).reply(200); + Api.postProjectApprovalRule(TEST_PROJECT_ID) + .then(done) + .catch(done.fail); + }); + }); + + describe('putProjectApprovalRule', () => { + it('puts with projectApprovalRulePath', done => { + const rule = { name: 'Lorem' }; + const expectedUrl = `${TEST_HOST}${Api.projectApprovalRulePath}` + .replace(':version', TEST_API_VERSION) + .replace(':id', TEST_PROJECT_ID) + .replace(':ruleid', TEST_RULE_ID); + + mock.onPut(expectedUrl).reply(200); + Api.putProjectApprovalRule(TEST_PROJECT_ID, TEST_RULE_ID, rule) + .then(() => { + expect(mock.history.put.length).toBe(1); + expect(mock.history.put[0].data).toBe(JSON.stringify(rule)); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('deleteProjectApprovalRule', () => { + it('deletes with projectApprovalRulePath', done => { + const expectedUrl = `${TEST_HOST}${Api.projectApprovalRulePath}` + .replace(':version', TEST_API_VERSION) + .replace(':id', TEST_PROJECT_ID) + .replace(':ruleid', TEST_RULE_ID); + + mock.onDelete(expectedUrl).reply(200); + Api.deleteProjectApprovalRule(TEST_PROJECT_ID, TEST_RULE_ID) + .then(done) + .catch(done.fail); + }); + }); +}); diff --git a/ee/spec/javascripts/approvals/stores/actions_spec.js b/ee/spec/javascripts/approvals/stores/actions_spec.js index 08348ca7459aea..5a493f2db3632d 100644 --- a/ee/spec/javascripts/approvals/stores/actions_spec.js +++ b/ee/spec/javascripts/approvals/stores/actions_spec.js @@ -1,9 +1,10 @@ +import Api from 'ee/api'; import testAction from 'spec/helpers/vuex_action_helper'; import * as types from 'ee/approvals/stores/mutation_types'; import actionsModule, * as actions from 'ee/approvals/stores/actions'; -import service from 'ee/approvals/services/approvals_service_stub'; import { mapApprovalRuleRequest, mapApprovalRulesResponse } from 'ee/approvals/mappers'; +const TEST_PROJECT_ID = 9; const TEST_RULE_ID = 7; const TEST_RULE_REQUEST = { name: 'Lorem', @@ -21,14 +22,18 @@ const TEST_RULE_RESPONSE = { }; describe('EE approvals store actions', () => { + let state; let flashSpy; beforeEach(() => { + state = { + settings: { projectId: TEST_PROJECT_ID }, + }; flashSpy = spyOnDependency(actionsModule, 'createFlash'); - spyOn(service, 'getProjectApprovalRules'); - spyOn(service, 'postProjectApprovalRule'); - spyOn(service, 'putProjectApprovalRule'); - spyOn(service, 'deleteProjectApprovalRule'); + spyOn(Api, 'getProjectApprovalRules'); + spyOn(Api, 'postProjectApprovalRule'); + spyOn(Api, 'putProjectApprovalRule'); + spyOn(Api, 'deleteProjectApprovalRule'); }); describe('setSettings', () => { @@ -94,28 +99,32 @@ describe('EE approvals store actions', () => { const response = { data: { rules: [TEST_RULE_RESPONSE] }, }; - service.getProjectApprovalRules.and.returnValue(Promise.resolve(response)); + Api.getProjectApprovalRules.and.returnValue(Promise.resolve(response)); testAction( actions.fetchRules, null, - {}, + state, [], [ { type: 'requestRules' }, { type: 'receiveRulesSuccess', payload: mapApprovalRulesResponse(response.data) }, ], - done, + () => { + expect(Api.getProjectApprovalRules).toHaveBeenCalledWith(TEST_PROJECT_ID); + + done(); + }, ); }); it('dispatches request/receive on error', done => { - service.getProjectApprovalRules.and.returnValue(Promise.reject()); + Api.getProjectApprovalRules.and.returnValue(Promise.reject()); testAction( actions.fetchRules, null, - {}, + state, [], [{ type: 'requestRules' }, { type: 'receiveRulesError' }], done, @@ -148,53 +157,73 @@ describe('EE approvals store actions', () => { describe('postRule', () => { it('dispatches success on success', done => { - service.postProjectApprovalRule.and.callFake(data => { - expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); - return Promise.resolve(); - }); + Api.postProjectApprovalRule.and.returnValue(Promise.resolve()); - testAction(actions.postRule, TEST_RULE_REQUEST, {}, [], [{ type: 'postRuleSuccess' }], done); + testAction( + actions.postRule, + TEST_RULE_REQUEST, + state, + [], + [{ type: 'postRuleSuccess' }], + () => { + expect(Api.postProjectApprovalRule).toHaveBeenCalledWith( + TEST_PROJECT_ID, + mapApprovalRuleRequest(TEST_RULE_REQUEST), + ); + done(); + }, + ); }); it('dispatches error on error', done => { - service.postProjectApprovalRule.and.callFake(data => { - expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); - return Promise.reject(); - }); + Api.postProjectApprovalRule.and.returnValue(Promise.reject()); - testAction(actions.postRule, TEST_RULE_REQUEST, {}, [], [{ type: 'postRuleError' }], done); + testAction( + actions.postRule, + TEST_RULE_REQUEST, + state, + [], + [{ type: 'postRuleError' }], + () => { + expect(Api.postProjectApprovalRule).toHaveBeenCalledWith( + TEST_PROJECT_ID, + mapApprovalRuleRequest(TEST_RULE_REQUEST), + ); + + done(); + }, + ); }); }); describe('putRule', () => { it('dispatches success on success', done => { - service.putProjectApprovalRule.and.callFake((id, data) => { - expect(id).toBe(TEST_RULE_ID); - expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); - return Promise.resolve(); - }); + Api.putProjectApprovalRule.and.returnValue(Promise.resolve()); testAction( actions.putRule, { id: TEST_RULE_ID, ...TEST_RULE_REQUEST }, - {}, + state, [], [{ type: 'postRuleSuccess' }], - done, + () => { + expect(Api.putProjectApprovalRule).toHaveBeenCalledWith( + TEST_PROJECT_ID, + TEST_RULE_ID, + mapApprovalRuleRequest(TEST_RULE_REQUEST), + ); + done(); + }, ); }); it('dispatches error on error', done => { - service.putProjectApprovalRule.and.callFake((id, data) => { - expect(id).toBe(TEST_RULE_ID); - expect(data).toEqual(mapApprovalRuleRequest(TEST_RULE_REQUEST)); - return Promise.reject(); - }); + Api.putProjectApprovalRule.and.returnValue(Promise.reject()); testAction( actions.putRule, { id: TEST_RULE_ID, ...TEST_RULE_REQUEST }, - {}, + state, [], [{ type: 'postRuleError' }], done, @@ -227,21 +256,26 @@ describe('EE approvals store actions', () => { describe('deleteRule', () => { it('dispatches success on success', done => { - service.deleteProjectApprovalRule.and.callFake(id => { - expect(id).toBe(TEST_RULE_ID); - return Promise.resolve(); - }); + Api.deleteProjectApprovalRule.and.returnValue(Promise.resolve()); - testAction(actions.deleteRule, TEST_RULE_ID, {}, [], [{ type: 'deleteRuleSuccess' }], done); + testAction( + actions.deleteRule, + TEST_RULE_ID, + state, + [], + [{ type: 'deleteRuleSuccess' }], + () => { + expect(Api.deleteProjectApprovalRule).toHaveBeenCalledWith(TEST_PROJECT_ID, TEST_RULE_ID); + + done(); + }, + ); }); it('dispatches error on error', done => { - service.deleteProjectApprovalRule.and.callFake(id => { - expect(id).toBe(TEST_RULE_ID); - return Promise.reject(); - }); + Api.deleteProjectApprovalRule.and.returnValue(Promise.reject()); - testAction(actions.deleteRule, TEST_RULE_ID, {}, [], [{ type: 'deleteRuleError' }], done); + testAction(actions.deleteRule, TEST_RULE_ID, state, [], [{ type: 'deleteRuleError' }], done); }); }); }); -- GitLab