summaryrefslogtreecommitdiff
path: root/spec/frontend/badges
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-25 21:09:23 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-25 21:09:23 +0000
commit32fd4cd5e2134511936899d6bcc4aaf18b9be6fd (patch)
tree10378ceffed52dd0e160a0d9bcf3c5ab72c18958 /spec/frontend/badges
parent951616a26a61e880860ad862c1d45a8e3762b4bc (diff)
downloadgitlab-ce-32fd4cd5e2134511936899d6bcc4aaf18b9be6fd.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/badges')
-rw-r--r--spec/frontend/badges/components/badge_form_spec.js197
-rw-r--r--spec/frontend/badges/components/badge_list_row_spec.js109
-rw-r--r--spec/frontend/badges/components/badge_list_spec.js95
-rw-r--r--spec/frontend/badges/components/badge_settings_spec.js117
-rw-r--r--spec/frontend/badges/components/badge_spec.js152
-rw-r--r--spec/frontend/badges/dummy_badge.js26
-rw-r--r--spec/frontend/badges/store/actions_spec.js622
-rw-r--r--spec/frontend/badges/store/mutations_spec.js418
8 files changed, 1736 insertions, 0 deletions
diff --git a/spec/frontend/badges/components/badge_form_spec.js b/spec/frontend/badges/components/badge_form_spec.js
new file mode 100644
index 00000000000..d61bd29ca9d
--- /dev/null
+++ b/spec/frontend/badges/components/badge_form_spec.js
@@ -0,0 +1,197 @@
+import Vue from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
+import axios from '~/lib/utils/axios_utils';
+import store from '~/badges/store';
+import createEmptyBadge from '~/badges/empty_badge';
+import BadgeForm from '~/badges/components/badge_form.vue';
+import { DUMMY_IMAGE_URL, TEST_HOST } from 'helpers/test_constants';
+
+// avoid preview background process
+BadgeForm.methods.debouncedPreview = () => {};
+
+describe('BadgeForm component', () => {
+ const Component = Vue.extend(BadgeForm);
+ let axiosMock;
+ let vm;
+
+ beforeEach(() => {
+ setFixtures(`
+ <div id="dummy-element"></div>
+ `);
+
+ axiosMock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ axiosMock.restore();
+ });
+
+ describe('methods', () => {
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, {
+ el: '#dummy-element',
+ store,
+ props: {
+ isEditing: false,
+ },
+ });
+ });
+
+ describe('onCancel', () => {
+ it('calls stopEditing', () => {
+ jest.spyOn(vm, 'stopEditing').mockImplementation(() => {});
+
+ vm.onCancel();
+
+ expect(vm.stopEditing).toHaveBeenCalled();
+ });
+ });
+ });
+
+ const sharedSubmitTests = submitAction => {
+ const nameSelector = '#badge-name';
+ const imageUrlSelector = '#badge-image-url';
+ const findImageUrlElement = () => vm.$el.querySelector(imageUrlSelector);
+ const linkUrlSelector = '#badge-link-url';
+ const findLinkUrlElement = () => vm.$el.querySelector(linkUrlSelector);
+ const setValue = (inputElementSelector, value) => {
+ const inputElement = vm.$el.querySelector(inputElementSelector);
+ inputElement.value = value;
+ inputElement.dispatchEvent(new Event('input'));
+ };
+ const submitForm = () => {
+ const submitButton = vm.$el.querySelector('button[type="submit"]');
+ submitButton.click();
+ };
+ const expectInvalidInput = inputElementSelector => {
+ const inputElement = vm.$el.querySelector(inputElementSelector);
+
+ expect(inputElement.checkValidity()).toBe(false);
+ const feedbackElement = vm.$el.querySelector(`${inputElementSelector} + .invalid-feedback`);
+
+ expect(feedbackElement).toBeVisible();
+ };
+
+ beforeEach(done => {
+ jest.spyOn(vm, submitAction).mockReturnValue(Promise.resolve());
+ store.replaceState({
+ ...store.state,
+ badgeInAddForm: createEmptyBadge(),
+ badgeInEditForm: createEmptyBadge(),
+ isSaving: false,
+ });
+
+ Vue.nextTick()
+ .then(() => {
+ 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', () => {
+ setValue(imageUrlSelector, '');
+
+ submitForm();
+
+ expectInvalidInput(imageUrlSelector);
+
+ expect(vm[submitAction]).not.toHaveBeenCalled();
+ });
+
+ it('returns immediately if imageUrl is malformed', () => {
+ setValue(imageUrlSelector, 'not-a-url');
+
+ submitForm();
+
+ expectInvalidInput(imageUrlSelector);
+
+ expect(vm[submitAction]).not.toHaveBeenCalled();
+ });
+
+ it('returns immediately if linkUrl is empty', () => {
+ setValue(linkUrlSelector, '');
+
+ submitForm();
+
+ expectInvalidInput(linkUrlSelector);
+
+ expect(vm[submitAction]).not.toHaveBeenCalled();
+ });
+
+ it('returns immediately if linkUrl is malformed', () => {
+ setValue(linkUrlSelector, 'not-a-url');
+
+ submitForm();
+
+ expectInvalidInput(linkUrlSelector);
+
+ expect(vm[submitAction]).not.toHaveBeenCalled();
+ });
+
+ it(`calls ${submitAction}`, () => {
+ submitForm();
+
+ expect(findImageUrlElement().checkValidity()).toBe(true);
+ expect(findLinkUrlElement().checkValidity()).toBe(true);
+ expect(vm[submitAction]).toHaveBeenCalled();
+ });
+ };
+
+ describe('if isEditing is false', () => {
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, {
+ el: '#dummy-element',
+ store,
+ props: {
+ isEditing: false,
+ },
+ });
+ });
+
+ it('renders one button', () => {
+ expect(vm.$el.querySelector('.row-content-block')).toBeNull();
+ const buttons = vm.$el.querySelectorAll('.form-group:last-of-type button');
+
+ expect(buttons.length).toBe(1);
+ const buttonAddElement = buttons[0];
+
+ expect(buttonAddElement).toBeVisible();
+ expect(buttonAddElement).toHaveText('Add badge');
+ });
+
+ sharedSubmitTests('addBadge');
+ });
+
+ describe('if isEditing is true', () => {
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, {
+ el: '#dummy-element',
+ store,
+ props: {
+ isEditing: true,
+ },
+ });
+ });
+
+ it('renders two buttons', () => {
+ const buttons = vm.$el.querySelectorAll('.row-content-block button');
+
+ expect(buttons.length).toBe(2);
+ const buttonSaveElement = buttons[0];
+
+ expect(buttonSaveElement).toBeVisible();
+ expect(buttonSaveElement).toHaveText('Save changes');
+ const buttonCancelElement = buttons[1];
+
+ expect(buttonCancelElement).toBeVisible();
+ expect(buttonCancelElement).toHaveText('Cancel');
+ });
+
+ sharedSubmitTests('saveBadge');
+ });
+});
diff --git a/spec/frontend/badges/components/badge_list_row_spec.js b/spec/frontend/badges/components/badge_list_row_spec.js
new file mode 100644
index 00000000000..31f0d850857
--- /dev/null
+++ b/spec/frontend/badges/components/badge_list_row_spec.js
@@ -0,0 +1,109 @@
+import Vue from 'vue';
+import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants';
+import store from '~/badges/store';
+import BadgeListRow from '~/badges/components/badge_list_row.vue';
+import { createDummyBadge } from '../dummy_badge';
+
+describe('BadgeListRow component', () => {
+ const Component = Vue.extend(BadgeListRow);
+ let badge;
+ let vm;
+
+ beforeEach(() => {
+ setFixtures(`
+ <div id="delete-badge-modal" class="modal"></div>
+ <div id="dummy-element"></div>
+ `);
+ store.replaceState({
+ ...store.state,
+ kind: PROJECT_BADGE,
+ });
+ badge = createDummyBadge();
+ vm = mountComponentWithStore(Component, {
+ el: '#dummy-element',
+ store,
+ props: { badge },
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders the badge', () => {
+ const badgeElement = vm.$el.querySelector('.project-badge');
+
+ expect(badgeElement).not.toBeNull();
+ expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl);
+ });
+
+ it('renders the badge name', () => {
+ expect(vm.$el.innerText).toMatch(badge.name);
+ });
+
+ it('renders the badge link', () => {
+ expect(vm.$el.innerText).toMatch(badge.linkUrl);
+ });
+
+ it('renders the badge kind', () => {
+ expect(vm.$el.innerText).toMatch('Project Badge');
+ });
+
+ it('shows edit and delete buttons', () => {
+ const buttons = vm.$el.querySelectorAll('.table-button-footer button');
+
+ expect(buttons).toHaveLength(2);
+ const buttonEditElement = buttons[0];
+
+ expect(buttonEditElement).toBeVisible();
+ expect(buttonEditElement).toHaveSpriteIcon('pencil');
+ const buttonDeleteElement = buttons[1];
+
+ expect(buttonDeleteElement).toBeVisible();
+ expect(buttonDeleteElement).toHaveSpriteIcon('remove');
+ });
+
+ it('calls editBadge when clicking then edit button', () => {
+ jest.spyOn(vm, 'editBadge').mockImplementation(() => {});
+
+ const editButton = vm.$el.querySelector('.table-button-footer button:first-of-type');
+ editButton.click();
+
+ expect(vm.editBadge).toHaveBeenCalled();
+ });
+
+ it('calls updateBadgeInModal and shows modal when clicking then delete button', done => {
+ jest.spyOn(vm, 'updateBadgeInModal').mockImplementation(() => {});
+
+ const deleteButton = vm.$el.querySelector('.table-button-footer button:last-of-type');
+ deleteButton.click();
+
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.updateBadgeInModal).toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ describe('for a group badge', () => {
+ beforeEach(done => {
+ badge.kind = GROUP_BADGE;
+
+ Vue.nextTick()
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('renders the badge kind', () => {
+ expect(vm.$el.innerText).toMatch('Group Badge');
+ });
+
+ it('hides edit and delete buttons', () => {
+ const buttons = vm.$el.querySelectorAll('.table-button-footer button');
+
+ expect(buttons).toHaveLength(0);
+ });
+ });
+});
diff --git a/spec/frontend/badges/components/badge_list_spec.js b/spec/frontend/badges/components/badge_list_spec.js
new file mode 100644
index 00000000000..5ffc046eb97
--- /dev/null
+++ b/spec/frontend/badges/components/badge_list_spec.js
@@ -0,0 +1,95 @@
+import Vue from 'vue';
+import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants';
+import store from '~/badges/store';
+import BadgeList from '~/badges/components/badge_list.vue';
+import { createDummyBadge } from '../dummy_badge';
+
+describe('BadgeList component', () => {
+ const Component = Vue.extend(BadgeList);
+ const numberOfDummyBadges = 3;
+ let vm;
+
+ beforeEach(() => {
+ setFixtures('<div id="dummy-element"></div>');
+ const badges = [];
+ for (let id = 0; id < numberOfDummyBadges; id += 1) {
+ badges.push({ id, ...createDummyBadge() });
+ }
+ store.replaceState({
+ ...store.state,
+ badges,
+ kind: PROJECT_BADGE,
+ isLoading: false,
+ });
+
+ // Can be removed once GlLoadingIcon no longer throws a warning
+ jest.spyOn(global.console, 'warn').mockImplementation(() => jest.fn());
+
+ vm = mountComponentWithStore(Component, {
+ el: '#dummy-element',
+ store,
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders a header with the badge count', () => {
+ const header = vm.$el.querySelector('.card-header');
+
+ expect(header).toHaveText(new RegExp(`Your badges\\s+${numberOfDummyBadges}`));
+ });
+
+ it('renders a row for each badge', () => {
+ const rows = vm.$el.querySelectorAll('.gl-responsive-table-row');
+
+ expect(rows).toHaveLength(numberOfDummyBadges);
+ });
+
+ it('renders a message if no badges exist', done => {
+ store.state.badges = [];
+
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.innerText).toMatch('This project has no badges');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('shows a loading icon when loading', done => {
+ store.state.isLoading = true;
+
+ Vue.nextTick()
+ .then(() => {
+ const loadingIcon = vm.$el.querySelector('.gl-spinner');
+
+ expect(loadingIcon).toBeVisible();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ describe('for group badges', () => {
+ beforeEach(done => {
+ store.state.kind = GROUP_BADGE;
+
+ Vue.nextTick()
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('renders a message if no badges exist', done => {
+ store.state.badges = [];
+
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.innerText).toMatch('This group has no badges');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/frontend/badges/components/badge_settings_spec.js b/spec/frontend/badges/components/badge_settings_spec.js
new file mode 100644
index 00000000000..8c3f1ea2749
--- /dev/null
+++ b/spec/frontend/badges/components/badge_settings_spec.js
@@ -0,0 +1,117 @@
+import Vue from 'vue';
+import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
+import store from '~/badges/store';
+import BadgeSettings from '~/badges/components/badge_settings.vue';
+import { createDummyBadge } from '../dummy_badge';
+
+describe('BadgeSettings component', () => {
+ const Component = Vue.extend(BadgeSettings);
+ let vm;
+
+ beforeEach(() => {
+ setFixtures(`
+ <div id="dummy-element"></div>
+ <button
+ id="dummy-modal-button"
+ type="button"
+ data-toggle="modal"
+ data-target="#delete-badge-modal"
+ >Show modal</button>
+ `);
+
+ // Can be removed once GlLoadingIcon no longer throws a warning
+ jest.spyOn(global.console, 'warn').mockImplementation(() => jest.fn());
+
+ vm = mountComponentWithStore(Component, {
+ el: '#dummy-element',
+ store,
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('displays modal if button is clicked', done => {
+ const badge = createDummyBadge();
+ store.state.badgeInModal = badge;
+ const modal = vm.$el.querySelector('#delete-badge-modal');
+ const button = document.getElementById('dummy-modal-button');
+
+ button.click();
+
+ Vue.nextTick()
+ .then(() => {
+ 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);
+ });
+
+ it('displays a form to add a badge', () => {
+ const form = vm.$el.querySelector('form:nth-of-type(2)');
+
+ expect(form).not.toBe(null);
+ const button = form.querySelector('.btn-success');
+
+ expect(button).not.toBe(null);
+ expect(button).toHaveText(/Add badge/);
+ });
+
+ it('displays badge list', () => {
+ const badgeListElement = vm.$el.querySelector('.card');
+
+ expect(badgeListElement).not.toBe(null);
+ expect(badgeListElement).toBeVisible();
+ expect(badgeListElement.innerText).toMatch('Your badges');
+ });
+
+ describe('when editing', () => {
+ beforeEach(done => {
+ store.state.isEditing = true;
+
+ Vue.nextTick()
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('displays a form to edit a badge', () => {
+ const form = vm.$el.querySelector('form:nth-of-type(1)');
+
+ expect(form).not.toBe(null);
+ const submitButton = form.querySelector('.btn-success');
+
+ expect(submitButton).not.toBe(null);
+ expect(submitButton).toHaveText(/Save changes/);
+ const cancelButton = form.querySelector('.btn-cancel');
+
+ expect(cancelButton).not.toBe(null);
+ expect(cancelButton).toHaveText(/Cancel/);
+ });
+
+ it('displays no badge list', () => {
+ const badgeListElement = vm.$el.querySelector('.card');
+
+ expect(badgeListElement).toBeHidden();
+ });
+ });
+
+ describe('methods', () => {
+ describe('onSubmitModal', () => {
+ it('triggers ', () => {
+ jest.spyOn(vm, 'deleteBadge').mockImplementation(() => Promise.resolve());
+ const modal = vm.$el.querySelector('#delete-badge-modal');
+ const deleteButton = modal.querySelector('.btn-danger');
+
+ deleteButton.click();
+
+ const badge = store.state.badgeInModal;
+
+ expect(vm.deleteBadge).toHaveBeenCalledWith(badge);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/badges/components/badge_spec.js b/spec/frontend/badges/components/badge_spec.js
new file mode 100644
index 00000000000..43004004fb2
--- /dev/null
+++ b/spec/frontend/badges/components/badge_spec.js
@@ -0,0 +1,152 @@
+import Vue from 'vue';
+import mountComponent from 'helpers/vue_mount_component_helper';
+import { DUMMY_IMAGE_URL, TEST_HOST } from 'spec/test_constants';
+import Badge from '~/badges/components/badge.vue';
+
+describe('Badge component', () => {
+ const Component = Vue.extend(Badge);
+ const dummyProps = {
+ imageUrl: DUMMY_IMAGE_URL,
+ linkUrl: `${TEST_HOST}/badge/link/url`,
+ };
+ let vm;
+
+ const findElements = () => {
+ const buttons = vm.$el.querySelectorAll('button');
+ return {
+ badgeImage: vm.$el.querySelector('img.project-badge'),
+ loadingIcon: vm.$el.querySelector('.gl-spinner'),
+ reloadButton: buttons[buttons.length - 1],
+ };
+ };
+
+ const createComponent = (props, el = null) => {
+ vm = mountComponent(Component, props, el);
+ const { badgeImage } = findElements();
+ return new Promise(resolve => {
+ badgeImage.addEventListener('load', resolve);
+ // Manually dispatch load event as it is not triggered
+ badgeImage.dispatchEvent(new Event('load'));
+ }).then(() => Vue.nextTick());
+ };
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('watchers', () => {
+ describe('imageUrl', () => {
+ it('sets isLoading and resets numRetries and hasError', done => {
+ const props = { ...dummyProps };
+ createComponent(props)
+ .then(() => {
+ expect(vm.isLoading).toBe(false);
+ vm.hasError = true;
+ vm.numRetries = 42;
+
+ vm.imageUrl = `${props.imageUrl}#something/else`;
+
+ return Vue.nextTick();
+ })
+ .then(() => {
+ expect(vm.isLoading).toBe(true);
+ expect(vm.numRetries).toBe(0);
+ expect(vm.hasError).toBe(false);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+
+ describe('methods', () => {
+ beforeEach(done => {
+ createComponent({ ...dummyProps })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('onError resets isLoading and sets hasError', () => {
+ vm.hasError = false;
+ vm.isLoading = true;
+
+ vm.onError();
+
+ expect(vm.hasError).toBe(true);
+ expect(vm.isLoading).toBe(false);
+ });
+
+ it('onLoad sets isLoading', () => {
+ vm.isLoading = true;
+
+ vm.onLoad();
+
+ expect(vm.isLoading).toBe(false);
+ });
+
+ it('reloadImage resets isLoading and hasError and increases numRetries', () => {
+ vm.hasError = true;
+ vm.isLoading = false;
+ vm.numRetries = 0;
+
+ vm.reloadImage();
+
+ expect(vm.hasError).toBe(false);
+ expect(vm.isLoading).toBe(true);
+ expect(vm.numRetries).toBe(1);
+ });
+ });
+
+ describe('behavior', () => {
+ beforeEach(done => {
+ setFixtures('<div id="dummy-element"></div>');
+ createComponent({ ...dummyProps }, '#dummy-element')
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('shows a badge image after loading', () => {
+ expect(vm.isLoading).toBe(false);
+ expect(vm.hasError).toBe(false);
+ const { badgeImage, loadingIcon, reloadButton } = findElements();
+
+ expect(badgeImage).toBeVisible();
+ expect(loadingIcon).toBeHidden();
+ expect(reloadButton).toBeHidden();
+ expect(vm.$el.querySelector('.btn-group')).toBeHidden();
+ });
+
+ it('shows a loading icon when loading', done => {
+ vm.isLoading = true;
+
+ Vue.nextTick()
+ .then(() => {
+ const { badgeImage, loadingIcon, reloadButton } = findElements();
+
+ expect(badgeImage).toBeHidden();
+ expect(loadingIcon).toBeVisible();
+ expect(reloadButton).toBeHidden();
+ expect(vm.$el.querySelector('.btn-group')).toBeHidden();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('shows an error and reload button if loading failed', done => {
+ vm.hasError = true;
+
+ Vue.nextTick()
+ .then(() => {
+ const { badgeImage, loadingIcon, reloadButton } = findElements();
+
+ expect(badgeImage).toBeHidden();
+ expect(loadingIcon).toBeHidden();
+ expect(reloadButton).toBeVisible();
+ expect(reloadButton).toHaveSpriteIcon('retry');
+ expect(vm.$el.innerText.trim()).toBe('No badge image');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/frontend/badges/dummy_badge.js b/spec/frontend/badges/dummy_badge.js
new file mode 100644
index 00000000000..a0dee89736e
--- /dev/null
+++ b/spec/frontend/badges/dummy_badge.js
@@ -0,0 +1,26 @@
+import { uniqueId } from 'lodash';
+import { DUMMY_IMAGE_URL, TEST_HOST } from 'spec/test_constants';
+import { PROJECT_BADGE } from '~/badges/constants';
+
+export const createDummyBadge = () => {
+ const id = uniqueId();
+ return {
+ id,
+ name: 'TestBadge',
+ imageUrl: `${TEST_HOST}/badges/${id}/image/url`,
+ isDeleting: false,
+ linkUrl: `${TEST_HOST}/badges/${id}/link/url`,
+ kind: PROJECT_BADGE,
+ renderedImageUrl: `${DUMMY_IMAGE_URL}?id=${id}`,
+ renderedLinkUrl: `${TEST_HOST}/badges/${id}/rendered/link/url`,
+ };
+};
+
+export const createDummyBadgeResponse = () => ({
+ name: 'TestBadge',
+ image_url: `${TEST_HOST}/badge/image/url`,
+ link_url: `${TEST_HOST}/badge/link/url`,
+ kind: PROJECT_BADGE,
+ rendered_image_url: DUMMY_IMAGE_URL,
+ rendered_link_url: `${TEST_HOST}/rendered/badge/link/url`,
+});
diff --git a/spec/frontend/badges/store/actions_spec.js b/spec/frontend/badges/store/actions_spec.js
new file mode 100644
index 00000000000..921c21cb55e
--- /dev/null
+++ b/spec/frontend/badges/store/actions_spec.js
@@ -0,0 +1,622 @@
+import MockAdapter from 'axios-mock-adapter';
+import { TEST_HOST } from 'spec/test_constants';
+import testAction from 'helpers/vuex_action_helper';
+import axios from '~/lib/utils/axios_utils';
+import actions, { transformBackendBadge } from '~/badges/store/actions';
+import mutationTypes from '~/badges/store/mutation_types';
+import createState from '~/badges/store/state';
+import { createDummyBadge, createDummyBadgeResponse } from '../dummy_badge';
+
+describe('Badges store actions', () => {
+ const dummyEndpointUrl = `${TEST_HOST}/badges/endpoint`;
+ const dummyBadges = [{ ...createDummyBadge(), id: 5 }, { ...createDummyBadge(), id: 6 }];
+
+ let axiosMock;
+ let badgeId;
+ let state;
+
+ beforeEach(() => {
+ axiosMock = new MockAdapter(axios);
+ state = {
+ ...createState(),
+ apiEndpointUrl: dummyEndpointUrl,
+ badges: dummyBadges,
+ };
+ badgeId = state.badges[0].id;
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ });
+
+ describe('requestNewBadge', () => {
+ it('commits REQUEST_NEW_BADGE', done => {
+ testAction(
+ actions.requestNewBadge,
+ null,
+ state,
+ [{ type: mutationTypes.REQUEST_NEW_BADGE }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveNewBadge', () => {
+ it('commits RECEIVE_NEW_BADGE', done => {
+ const newBadge = createDummyBadge();
+ testAction(
+ actions.receiveNewBadge,
+ newBadge,
+ state,
+ [{ type: mutationTypes.RECEIVE_NEW_BADGE, payload: newBadge }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveNewBadgeError', () => {
+ it('commits RECEIVE_NEW_BADGE_ERROR', done => {
+ testAction(
+ actions.receiveNewBadgeError,
+ null,
+ state,
+ [{ type: mutationTypes.RECEIVE_NEW_BADGE_ERROR }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('addBadge', () => {
+ let badgeInAddForm;
+ let dispatch;
+ let endpointMock;
+
+ beforeEach(() => {
+ endpointMock = axiosMock.onPost(dummyEndpointUrl);
+ dispatch = jest.fn();
+ badgeInAddForm = createDummyBadge();
+ state = {
+ ...state,
+ badgeInAddForm,
+ };
+ });
+
+ it('dispatches requestNewBadge and receiveNewBadge for successful response', done => {
+ const dummyResponse = createDummyBadgeResponse();
+
+ endpointMock.replyOnce(req => {
+ expect(req.data).toBe(
+ JSON.stringify({
+ name: 'TestBadge',
+ image_url: badgeInAddForm.imageUrl,
+ link_url: badgeInAddForm.linkUrl,
+ }),
+ );
+
+ expect(dispatch.mock.calls).toEqual([['requestNewBadge']]);
+ dispatch.mockClear();
+ return [200, dummyResponse];
+ });
+
+ const dummyBadge = transformBackendBadge(dummyResponse);
+ actions
+ .addBadge({ state, dispatch })
+ .then(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveNewBadge', dummyBadge]]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('dispatches requestNewBadge and receiveNewBadgeError for error response', done => {
+ endpointMock.replyOnce(req => {
+ expect(req.data).toBe(
+ JSON.stringify({
+ name: 'TestBadge',
+ image_url: badgeInAddForm.imageUrl,
+ link_url: badgeInAddForm.linkUrl,
+ }),
+ );
+
+ expect(dispatch.mock.calls).toEqual([['requestNewBadge']]);
+ dispatch.mockClear();
+ return [500, ''];
+ });
+
+ actions
+ .addBadge({ state, dispatch })
+ .then(() => done.fail('Expected Ajax call to fail!'))
+ .catch(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveNewBadgeError']]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('requestDeleteBadge', () => {
+ it('commits REQUEST_DELETE_BADGE', done => {
+ testAction(
+ actions.requestDeleteBadge,
+ badgeId,
+ state,
+ [{ type: mutationTypes.REQUEST_DELETE_BADGE, payload: badgeId }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveDeleteBadge', () => {
+ it('commits RECEIVE_DELETE_BADGE', done => {
+ testAction(
+ actions.receiveDeleteBadge,
+ badgeId,
+ state,
+ [{ type: mutationTypes.RECEIVE_DELETE_BADGE, payload: badgeId }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveDeleteBadgeError', () => {
+ it('commits RECEIVE_DELETE_BADGE_ERROR', done => {
+ testAction(
+ actions.receiveDeleteBadgeError,
+ badgeId,
+ state,
+ [{ type: mutationTypes.RECEIVE_DELETE_BADGE_ERROR, payload: badgeId }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('deleteBadge', () => {
+ let dispatch;
+ let endpointMock;
+
+ beforeEach(() => {
+ endpointMock = axiosMock.onDelete(`${dummyEndpointUrl}/${badgeId}`);
+ dispatch = jest.fn();
+ });
+
+ it('dispatches requestDeleteBadge and receiveDeleteBadge for successful response', done => {
+ endpointMock.replyOnce(() => {
+ expect(dispatch.mock.calls).toEqual([['requestDeleteBadge', badgeId]]);
+ dispatch.mockClear();
+ return [200, ''];
+ });
+
+ actions
+ .deleteBadge({ state, dispatch }, { id: badgeId })
+ .then(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveDeleteBadge', badgeId]]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('dispatches requestDeleteBadge and receiveDeleteBadgeError for error response', done => {
+ endpointMock.replyOnce(() => {
+ expect(dispatch.mock.calls).toEqual([['requestDeleteBadge', badgeId]]);
+ dispatch.mockClear();
+ return [500, ''];
+ });
+
+ actions
+ .deleteBadge({ state, dispatch }, { id: badgeId })
+ .then(() => done.fail('Expected Ajax call to fail!'))
+ .catch(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveDeleteBadgeError', badgeId]]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('editBadge', () => {
+ it('commits START_EDITING', done => {
+ const dummyBadge = createDummyBadge();
+ testAction(
+ actions.editBadge,
+ dummyBadge,
+ state,
+ [{ type: mutationTypes.START_EDITING, payload: dummyBadge }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('requestLoadBadges', () => {
+ it('commits REQUEST_LOAD_BADGES', done => {
+ const dummyData = 'this is not real data';
+ testAction(
+ actions.requestLoadBadges,
+ dummyData,
+ state,
+ [{ type: mutationTypes.REQUEST_LOAD_BADGES, payload: dummyData }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveLoadBadges', () => {
+ it('commits RECEIVE_LOAD_BADGES', done => {
+ const badges = dummyBadges;
+ testAction(
+ actions.receiveLoadBadges,
+ badges,
+ state,
+ [{ type: mutationTypes.RECEIVE_LOAD_BADGES, payload: badges }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveLoadBadgesError', () => {
+ it('commits RECEIVE_LOAD_BADGES_ERROR', done => {
+ testAction(
+ actions.receiveLoadBadgesError,
+ null,
+ state,
+ [{ type: mutationTypes.RECEIVE_LOAD_BADGES_ERROR }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('loadBadges', () => {
+ let dispatch;
+ let endpointMock;
+
+ beforeEach(() => {
+ endpointMock = axiosMock.onGet(dummyEndpointUrl);
+ dispatch = jest.fn();
+ });
+
+ it('dispatches requestLoadBadges and receiveLoadBadges for successful response', done => {
+ const dummyData = 'this is just some data';
+ const dummyReponse = [
+ createDummyBadgeResponse(),
+ createDummyBadgeResponse(),
+ createDummyBadgeResponse(),
+ ];
+ endpointMock.replyOnce(() => {
+ expect(dispatch.mock.calls).toEqual([['requestLoadBadges', dummyData]]);
+ dispatch.mockClear();
+ return [200, dummyReponse];
+ });
+
+ actions
+ .loadBadges({ state, dispatch }, dummyData)
+ .then(() => {
+ const badges = dummyReponse.map(transformBackendBadge);
+
+ expect(dispatch.mock.calls).toEqual([['receiveLoadBadges', badges]]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('dispatches requestLoadBadges and receiveLoadBadgesError for error response', done => {
+ const dummyData = 'this is just some data';
+ endpointMock.replyOnce(() => {
+ expect(dispatch.mock.calls).toEqual([['requestLoadBadges', dummyData]]);
+ dispatch.mockClear();
+ return [500, ''];
+ });
+
+ actions
+ .loadBadges({ state, dispatch }, dummyData)
+ .then(() => done.fail('Expected Ajax call to fail!'))
+ .catch(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveLoadBadgesError']]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('requestRenderedBadge', () => {
+ it('commits REQUEST_RENDERED_BADGE', done => {
+ testAction(
+ actions.requestRenderedBadge,
+ null,
+ state,
+ [{ type: mutationTypes.REQUEST_RENDERED_BADGE }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveRenderedBadge', () => {
+ it('commits RECEIVE_RENDERED_BADGE', done => {
+ const dummyBadge = createDummyBadge();
+ testAction(
+ actions.receiveRenderedBadge,
+ dummyBadge,
+ state,
+ [{ type: mutationTypes.RECEIVE_RENDERED_BADGE, payload: dummyBadge }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveRenderedBadgeError', () => {
+ it('commits RECEIVE_RENDERED_BADGE_ERROR', done => {
+ testAction(
+ actions.receiveRenderedBadgeError,
+ null,
+ state,
+ [{ type: mutationTypes.RECEIVE_RENDERED_BADGE_ERROR }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('renderBadge', () => {
+ let dispatch;
+ let endpointMock;
+ let badgeInForm;
+
+ beforeEach(() => {
+ badgeInForm = createDummyBadge();
+ state = {
+ ...state,
+ badgeInAddForm: badgeInForm,
+ };
+ const urlParameters = [
+ `link_url=${encodeURIComponent(badgeInForm.linkUrl)}`,
+ `image_url=${encodeURIComponent(badgeInForm.imageUrl)}`,
+ ].join('&');
+ endpointMock = axiosMock.onGet(`${dummyEndpointUrl}/render?${urlParameters}`);
+ dispatch = jest.fn();
+ });
+
+ it('returns immediately if imageUrl is empty', done => {
+ jest.spyOn(axios, 'get').mockImplementation(() => {});
+ badgeInForm.imageUrl = '';
+
+ actions
+ .renderBadge({ state, dispatch })
+ .then(() => {
+ expect(axios.get).not.toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('returns immediately if linkUrl is empty', done => {
+ jest.spyOn(axios, 'get').mockImplementation(() => {});
+ badgeInForm.linkUrl = '';
+
+ actions
+ .renderBadge({ state, dispatch })
+ .then(() => {
+ expect(axios.get).not.toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('escapes user input', done => {
+ jest
+ .spyOn(axios, 'get')
+ .mockImplementation(() => Promise.resolve({ data: createDummyBadgeResponse() }));
+ badgeInForm.imageUrl = '&make-sandwich=true';
+ badgeInForm.linkUrl = '<script>I am dangerous!</script>';
+
+ actions
+ .renderBadge({ state, dispatch })
+ .then(() => {
+ expect(axios.get.mock.calls.length).toBe(1);
+ const url = axios.get.mock.calls[0][0];
+
+ expect(url).toMatch(new RegExp(`^${dummyEndpointUrl}/render?`));
+ expect(url).toMatch(
+ new RegExp('\\?link_url=%3Cscript%3EI%20am%20dangerous!%3C%2Fscript%3E&'),
+ );
+ expect(url).toMatch(new RegExp('&image_url=%26make-sandwich%3Dtrue$'));
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('dispatches requestRenderedBadge and receiveRenderedBadge for successful response', done => {
+ const dummyReponse = createDummyBadgeResponse();
+ endpointMock.replyOnce(() => {
+ expect(dispatch.mock.calls).toEqual([['requestRenderedBadge']]);
+ dispatch.mockClear();
+ return [200, dummyReponse];
+ });
+
+ actions
+ .renderBadge({ state, dispatch })
+ .then(() => {
+ const renderedBadge = transformBackendBadge(dummyReponse);
+
+ expect(dispatch.mock.calls).toEqual([['receiveRenderedBadge', renderedBadge]]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('dispatches requestRenderedBadge and receiveRenderedBadgeError for error response', done => {
+ endpointMock.replyOnce(() => {
+ expect(dispatch.mock.calls).toEqual([['requestRenderedBadge']]);
+ dispatch.mockClear();
+ return [500, ''];
+ });
+
+ actions
+ .renderBadge({ state, dispatch })
+ .then(() => done.fail('Expected Ajax call to fail!'))
+ .catch(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveRenderedBadgeError']]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('requestUpdatedBadge', () => {
+ it('commits REQUEST_UPDATED_BADGE', done => {
+ testAction(
+ actions.requestUpdatedBadge,
+ null,
+ state,
+ [{ type: mutationTypes.REQUEST_UPDATED_BADGE }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveUpdatedBadge', () => {
+ it('commits RECEIVE_UPDATED_BADGE', done => {
+ const updatedBadge = createDummyBadge();
+ testAction(
+ actions.receiveUpdatedBadge,
+ updatedBadge,
+ state,
+ [{ type: mutationTypes.RECEIVE_UPDATED_BADGE, payload: updatedBadge }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveUpdatedBadgeError', () => {
+ it('commits RECEIVE_UPDATED_BADGE_ERROR', done => {
+ testAction(
+ actions.receiveUpdatedBadgeError,
+ null,
+ state,
+ [{ type: mutationTypes.RECEIVE_UPDATED_BADGE_ERROR }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('saveBadge', () => {
+ let badgeInEditForm;
+ let dispatch;
+ let endpointMock;
+
+ beforeEach(() => {
+ badgeInEditForm = createDummyBadge();
+ state = {
+ ...state,
+ badgeInEditForm,
+ };
+ endpointMock = axiosMock.onPut(`${dummyEndpointUrl}/${badgeInEditForm.id}`);
+ dispatch = jest.fn();
+ });
+
+ it('dispatches requestUpdatedBadge and receiveUpdatedBadge for successful response', done => {
+ const dummyResponse = createDummyBadgeResponse();
+
+ endpointMock.replyOnce(req => {
+ expect(req.data).toBe(
+ JSON.stringify({
+ name: 'TestBadge',
+ image_url: badgeInEditForm.imageUrl,
+ link_url: badgeInEditForm.linkUrl,
+ }),
+ );
+
+ expect(dispatch.mock.calls).toEqual([['requestUpdatedBadge']]);
+ dispatch.mockClear();
+ return [200, dummyResponse];
+ });
+
+ const updatedBadge = transformBackendBadge(dummyResponse);
+ actions
+ .saveBadge({ state, dispatch })
+ .then(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveUpdatedBadge', updatedBadge]]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('dispatches requestUpdatedBadge and receiveUpdatedBadgeError for error response', done => {
+ endpointMock.replyOnce(req => {
+ expect(req.data).toBe(
+ JSON.stringify({
+ name: 'TestBadge',
+ image_url: badgeInEditForm.imageUrl,
+ link_url: badgeInEditForm.linkUrl,
+ }),
+ );
+
+ expect(dispatch.mock.calls).toEqual([['requestUpdatedBadge']]);
+ dispatch.mockClear();
+ return [500, ''];
+ });
+
+ actions
+ .saveBadge({ state, dispatch })
+ .then(() => done.fail('Expected Ajax call to fail!'))
+ .catch(() => {
+ expect(dispatch.mock.calls).toEqual([['receiveUpdatedBadgeError']]);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('stopEditing', () => {
+ it('commits STOP_EDITING', done => {
+ testAction(
+ actions.stopEditing,
+ null,
+ state,
+ [{ type: mutationTypes.STOP_EDITING }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('updateBadgeInForm', () => {
+ it('commits UPDATE_BADGE_IN_FORM', done => {
+ const dummyBadge = createDummyBadge();
+ testAction(
+ actions.updateBadgeInForm,
+ dummyBadge,
+ state,
+ [{ type: mutationTypes.UPDATE_BADGE_IN_FORM, payload: dummyBadge }],
+ [],
+ done,
+ );
+ });
+
+ describe('updateBadgeInModal', () => {
+ it('commits UPDATE_BADGE_IN_MODAL', done => {
+ const dummyBadge = createDummyBadge();
+ testAction(
+ actions.updateBadgeInModal,
+ dummyBadge,
+ state,
+ [{ type: mutationTypes.UPDATE_BADGE_IN_MODAL, payload: dummyBadge }],
+ [],
+ done,
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/badges/store/mutations_spec.js b/spec/frontend/badges/store/mutations_spec.js
new file mode 100644
index 00000000000..8d26f83339d
--- /dev/null
+++ b/spec/frontend/badges/store/mutations_spec.js
@@ -0,0 +1,418 @@
+import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants';
+import store from '~/badges/store';
+import types from '~/badges/store/mutation_types';
+import createState from '~/badges/store/state';
+import { createDummyBadge } from '../dummy_badge';
+
+describe('Badges store mutations', () => {
+ let dummyBadge;
+
+ beforeEach(() => {
+ dummyBadge = createDummyBadge();
+ store.replaceState(createState());
+ });
+
+ describe('RECEIVE_DELETE_BADGE', () => {
+ beforeEach(() => {
+ const badges = [
+ { ...dummyBadge, id: dummyBadge.id - 1 },
+ dummyBadge,
+ { ...dummyBadge, id: dummyBadge.id + 1 },
+ ];
+
+ store.replaceState({
+ ...store.state,
+ badges,
+ });
+ });
+
+ it('removes deleted badge', () => {
+ const badgeCount = store.state.badges.length;
+
+ store.commit(types.RECEIVE_DELETE_BADGE, dummyBadge.id);
+
+ expect(store.state.badges.length).toBe(badgeCount - 1);
+ expect(store.state.badges.indexOf(dummyBadge)).toBe(-1);
+ });
+ });
+
+ describe('RECEIVE_DELETE_BADGE_ERROR', () => {
+ beforeEach(() => {
+ const badges = [
+ { ...dummyBadge, id: dummyBadge.id - 1, isDeleting: false },
+ { ...dummyBadge, isDeleting: true },
+ { ...dummyBadge, id: dummyBadge.id + 1, isDeleting: true },
+ ];
+
+ store.replaceState({
+ ...store.state,
+ badges,
+ });
+ });
+
+ it('sets isDeleting to false', () => {
+ const badgeCount = store.state.badges.length;
+
+ store.commit(types.RECEIVE_DELETE_BADGE_ERROR, dummyBadge.id);
+
+ expect(store.state.badges.length).toBe(badgeCount);
+ expect(store.state.badges[0].isDeleting).toBe(false);
+ expect(store.state.badges[1].isDeleting).toBe(false);
+ expect(store.state.badges[2].isDeleting).toBe(true);
+ });
+ });
+
+ describe('RECEIVE_LOAD_BADGES', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isLoading: 'not false',
+ });
+ });
+
+ it('sets badges and isLoading to false', () => {
+ const badges = [createDummyBadge()];
+ store.commit(types.RECEIVE_LOAD_BADGES, badges);
+
+ expect(store.state.isLoading).toBe(false);
+ expect(store.state.badges).toBe(badges);
+ });
+ });
+
+ describe('RECEIVE_LOAD_BADGES_ERROR', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isLoading: 'not false',
+ });
+ });
+
+ it('sets isLoading to false', () => {
+ store.commit(types.RECEIVE_LOAD_BADGES_ERROR);
+
+ expect(store.state.isLoading).toBe(false);
+ });
+ });
+
+ describe('RECEIVE_NEW_BADGE', () => {
+ beforeEach(() => {
+ const badges = [
+ { ...dummyBadge, id: dummyBadge.id - 1, kind: GROUP_BADGE },
+ { ...dummyBadge, id: dummyBadge.id + 1, kind: GROUP_BADGE },
+ { ...dummyBadge, id: dummyBadge.id - 1, kind: PROJECT_BADGE },
+ { ...dummyBadge, id: dummyBadge.id + 1, kind: PROJECT_BADGE },
+ ];
+ store.replaceState({
+ ...store.state,
+ badgeInAddForm: createDummyBadge(),
+ badges,
+ isSaving: 'dummy value',
+ renderedBadge: createDummyBadge(),
+ });
+ });
+
+ it('resets the add form', () => {
+ store.commit(types.RECEIVE_NEW_BADGE, dummyBadge);
+
+ expect(store.state.badgeInAddForm).toBe(null);
+ expect(store.state.isSaving).toBe(false);
+ expect(store.state.renderedBadge).toBe(null);
+ });
+
+ it('inserts group badge at correct position', () => {
+ const badgeCount = store.state.badges.length;
+ dummyBadge = { ...dummyBadge, kind: GROUP_BADGE };
+
+ store.commit(types.RECEIVE_NEW_BADGE, dummyBadge);
+
+ expect(store.state.badges.length).toBe(badgeCount + 1);
+ expect(store.state.badges.indexOf(dummyBadge)).toBe(1);
+ });
+
+ it('inserts project badge at correct position', () => {
+ const badgeCount = store.state.badges.length;
+ dummyBadge = { ...dummyBadge, kind: PROJECT_BADGE };
+
+ store.commit(types.RECEIVE_NEW_BADGE, dummyBadge);
+
+ expect(store.state.badges.length).toBe(badgeCount + 1);
+ expect(store.state.badges.indexOf(dummyBadge)).toBe(3);
+ });
+ });
+
+ describe('RECEIVE_NEW_BADGE_ERROR', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isSaving: 'dummy value',
+ });
+ });
+
+ it('sets isSaving to false', () => {
+ store.commit(types.RECEIVE_NEW_BADGE_ERROR);
+
+ expect(store.state.isSaving).toBe(false);
+ });
+ });
+
+ describe('RECEIVE_RENDERED_BADGE', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isRendering: 'dummy value',
+ renderedBadge: 'dummy value',
+ });
+ });
+
+ it('sets renderedBadge', () => {
+ store.commit(types.RECEIVE_RENDERED_BADGE, dummyBadge);
+
+ expect(store.state.isRendering).toBe(false);
+ expect(store.state.renderedBadge).toBe(dummyBadge);
+ });
+ });
+
+ describe('RECEIVE_RENDERED_BADGE_ERROR', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isRendering: 'dummy value',
+ });
+ });
+
+ it('sets isRendering to false', () => {
+ store.commit(types.RECEIVE_RENDERED_BADGE_ERROR);
+
+ expect(store.state.isRendering).toBe(false);
+ });
+ });
+
+ describe('RECEIVE_UPDATED_BADGE', () => {
+ beforeEach(() => {
+ const badges = [
+ { ...dummyBadge, id: dummyBadge.id - 1 },
+ dummyBadge,
+ { ...dummyBadge, id: dummyBadge.id + 1 },
+ ];
+ store.replaceState({
+ ...store.state,
+ badgeInEditForm: createDummyBadge(),
+ badges,
+ isEditing: 'dummy value',
+ isSaving: 'dummy value',
+ renderedBadge: createDummyBadge(),
+ });
+ });
+
+ it('resets the edit form', () => {
+ store.commit(types.RECEIVE_UPDATED_BADGE, dummyBadge);
+
+ expect(store.state.badgeInAddForm).toBe(null);
+ expect(store.state.isSaving).toBe(false);
+ expect(store.state.renderedBadge).toBe(null);
+ });
+
+ it('replaces the updated badge', () => {
+ const badgeCount = store.state.badges.length;
+ const badgeIndex = store.state.badges.indexOf(dummyBadge);
+ const newBadge = { id: dummyBadge.id, dummy: 'value' };
+
+ store.commit(types.RECEIVE_UPDATED_BADGE, newBadge);
+
+ expect(store.state.badges.length).toBe(badgeCount);
+ expect(store.state.badges[badgeIndex]).toBe(newBadge);
+ });
+ });
+
+ describe('RECEIVE_UPDATED_BADGE_ERROR', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isSaving: 'dummy value',
+ });
+ });
+
+ it('sets isSaving to false', () => {
+ store.commit(types.RECEIVE_NEW_BADGE_ERROR);
+
+ expect(store.state.isSaving).toBe(false);
+ });
+ });
+
+ describe('REQUEST_DELETE_BADGE', () => {
+ beforeEach(() => {
+ const badges = [
+ { ...dummyBadge, id: dummyBadge.id - 1, isDeleting: false },
+ { ...dummyBadge, isDeleting: false },
+ { ...dummyBadge, id: dummyBadge.id + 1, isDeleting: true },
+ ];
+
+ store.replaceState({
+ ...store.state,
+ badges,
+ });
+ });
+
+ it('sets isDeleting to true', () => {
+ const badgeCount = store.state.badges.length;
+
+ store.commit(types.REQUEST_DELETE_BADGE, dummyBadge.id);
+
+ expect(store.state.badges.length).toBe(badgeCount);
+ expect(store.state.badges[0].isDeleting).toBe(false);
+ expect(store.state.badges[1].isDeleting).toBe(true);
+ expect(store.state.badges[2].isDeleting).toBe(true);
+ });
+ });
+
+ describe('REQUEST_LOAD_BADGES', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ apiEndpointUrl: 'some endpoint',
+ docsUrl: 'some url',
+ isLoading: 'dummy value',
+ kind: 'some kind',
+ });
+ });
+
+ it('sets isLoading to true and initializes the store', () => {
+ const dummyData = {
+ apiEndpointUrl: 'dummy endpoint',
+ docsUrl: 'dummy url',
+ kind: 'dummy kind',
+ };
+
+ store.commit(types.REQUEST_LOAD_BADGES, dummyData);
+
+ expect(store.state.isLoading).toBe(true);
+ expect(store.state.apiEndpointUrl).toBe(dummyData.apiEndpointUrl);
+ expect(store.state.docsUrl).toBe(dummyData.docsUrl);
+ expect(store.state.kind).toBe(dummyData.kind);
+ });
+ });
+
+ describe('REQUEST_NEW_BADGE', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isSaving: 'dummy value',
+ });
+ });
+
+ it('sets isSaving to true', () => {
+ store.commit(types.REQUEST_NEW_BADGE);
+
+ expect(store.state.isSaving).toBe(true);
+ });
+ });
+
+ describe('REQUEST_RENDERED_BADGE', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isRendering: 'dummy value',
+ });
+ });
+
+ it('sets isRendering to true', () => {
+ store.commit(types.REQUEST_RENDERED_BADGE);
+
+ expect(store.state.isRendering).toBe(true);
+ });
+ });
+
+ describe('REQUEST_UPDATED_BADGE', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ isSaving: 'dummy value',
+ });
+ });
+
+ it('sets isSaving to true', () => {
+ store.commit(types.REQUEST_NEW_BADGE);
+
+ expect(store.state.isSaving).toBe(true);
+ });
+ });
+
+ describe('START_EDITING', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ badgeInEditForm: 'dummy value',
+ isEditing: 'dummy value',
+ renderedBadge: 'dummy value',
+ });
+ });
+
+ it('initializes the edit form', () => {
+ store.commit(types.START_EDITING, dummyBadge);
+
+ expect(store.state.isEditing).toBe(true);
+ expect(store.state.badgeInEditForm).toEqual(dummyBadge);
+ expect(store.state.renderedBadge).toEqual(dummyBadge);
+ });
+ });
+
+ describe('STOP_EDITING', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ badgeInEditForm: 'dummy value',
+ isEditing: 'dummy value',
+ renderedBadge: 'dummy value',
+ });
+ });
+
+ it('resets the edit form', () => {
+ store.commit(types.STOP_EDITING);
+
+ expect(store.state.isEditing).toBe(false);
+ expect(store.state.badgeInEditForm).toBe(null);
+ expect(store.state.renderedBadge).toBe(null);
+ });
+ });
+
+ describe('UPDATE_BADGE_IN_FORM', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ badgeInAddForm: 'dummy value',
+ badgeInEditForm: 'dummy value',
+ });
+ });
+
+ it('sets badgeInEditForm if isEditing is true', () => {
+ store.state.isEditing = true;
+
+ store.commit(types.UPDATE_BADGE_IN_FORM, dummyBadge);
+
+ expect(store.state.badgeInEditForm).toBe(dummyBadge);
+ });
+
+ it('sets badgeInAddForm if isEditing is false', () => {
+ store.state.isEditing = false;
+
+ store.commit(types.UPDATE_BADGE_IN_FORM, dummyBadge);
+
+ expect(store.state.badgeInAddForm).toBe(dummyBadge);
+ });
+ });
+
+ describe('UPDATE_BADGE_IN_MODAL', () => {
+ beforeEach(() => {
+ store.replaceState({
+ ...store.state,
+ badgeInModal: 'dummy value',
+ });
+ });
+
+ it('sets badgeInModal', () => {
+ store.commit(types.UPDATE_BADGE_IN_MODAL, dummyBadge);
+
+ expect(store.state.badgeInModal).toBe(dummyBadge);
+ });
+ });
+});