diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3a140658..9029afb8e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -448,7 +448,7 @@ jobs: report_name: Coverage Admin Interface type: lcov result_path: ./coverage/lcov.info - min_coverage: 78 + min_coverage: 81 token: ${{ github.token }} ############################################################################## diff --git a/admin/package.json b/admin/package.json index e38d21af8..11ca864c9 100644 --- a/admin/package.json +++ b/admin/package.json @@ -12,7 +12,7 @@ "dev": "yarn run serve", "build": "vue-cli-service build", "lint": "eslint --ext .js,.vue .", - "test": "jest --coverage", + "test": "TZ=UTC jest --coverage", "locales": "scripts/missing-keys.sh && scripts/sort.sh" }, "dependencies": { @@ -36,14 +36,12 @@ "graphql": "^15.6.1", "identity-obj-proxy": "^3.0.0", "jest": "26.6.3", - "moment": "^2.29.1", "regenerator-runtime": "^0.13.9", "stats-webpack-plugin": "^0.7.0", "vue": "^2.6.11", "vue-apollo": "^3.0.8", "vue-i18n": "^8.26.5", "vue-jest": "^3.0.7", - "vue-moment": "^4.1.0", "vue-router": "^3.5.3", "vue-toasted": "^1.1.28", "vuex": "^3.6.2", diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js index b3807b16f..cfc23fa26 100644 --- a/admin/src/components/CreationFormular.spec.js +++ b/admin/src/components/CreationFormular.spec.js @@ -5,14 +5,6 @@ import { createPendingCreations } from '../graphql/createPendingCreations' const localVue = global.localVue -const apolloMock = jest.fn().mockResolvedValue({ - data: { - verifyLogin: { - name: 'success', - id: 0, - }, - }, -}) const apolloMutateMock = jest.fn().mockResolvedValue({ data: { createPendingCreation: [0, 0, 0], @@ -23,19 +15,12 @@ const toastedErrorMock = jest.fn() const toastedSuccessMock = jest.fn() const mocks = { - $t: jest.fn((t) => t), - $moment: jest.fn(() => { - return { - format: jest.fn((m) => m), - subtract: jest.fn(() => { - return { - format: jest.fn((m) => m), - } - }), - } + $t: jest.fn((t, options) => (options ? [t, options] : t)), + $d: jest.fn((d) => { + const date = new Date(d) + return date.toISOString().split('T')[0] }), $apollo: { - query: apolloMock, mutate: apolloMutateMock, }, $store: { @@ -56,7 +41,12 @@ const mocks = { const propsData = { type: '', creation: [], - itemsMassCreation: {}, +} + +const now = new Date(Date.now()) +const getCreationDate = (sub) => { + const date = sub === 0 ? now : new Date(now.getFullYear(), now.getMonth() - sub, 1, 0) + return date.toISOString().split('T')[0] } describe('CreationFormular', () => { @@ -75,21 +65,24 @@ describe('CreationFormular', () => { expect(wrapper.find('.component-creation-formular').exists()).toBeTruthy() }) - describe('server sends back moderator data', () => { - it('called store commit with mocked data', () => { - expect(stateCommitMock).toBeCalledWith('moderator', { name: 'success', id: 0 }) - }) - }) - - describe('server throws error for moderator data call', () => { - beforeEach(() => { - jest.clearAllMocks() - apolloMock.mockRejectedValueOnce({ message: 'Ouch!' }) - wrapper = Wrapper() + describe('text and value form props', () => { + beforeEach(async () => { + wrapper = mount(CreationFormular, { + localVue, + mocks, + propsData: { + creationUserData: { memo: 'Memo from property', amount: 42 }, + ...propsData, + }, + }) }) - it('has called store commit with fake data', () => { - expect(stateCommitMock).toBeCalledWith('moderator', { id: 0, name: 'Test Moderator' }) + it('has text taken from props', () => { + expect(wrapper.vm.text).toBe('Memo from property') + }) + + it('has value taken from props', () => { + expect(wrapper.vm.value).toBe(42) }) }) @@ -98,52 +91,6 @@ describe('CreationFormular', () => { expect(wrapper.findAll('input[type="radio"]').length).toBe(3) }) - describe('with mass creation', () => { - beforeEach(async () => { - jest.clearAllMocks() - await wrapper.setProps({ type: 'massCreation', creation: [200, 400, 600] }) - await wrapper.setData({ rangeMin: 180 }) - await wrapper.setData({ text: 'Test create coins' }) - await wrapper.setData({ value: 90 }) - }) - - describe('first radio button', () => { - beforeEach(async () => { - await wrapper.findAll('input[type="radio"]').at(0).setChecked() - }) - - it('emits update-radio-selected with index 0', () => { - expect(wrapper.emitted()['update-radio-selected']).toEqual([ - [expect.arrayContaining([0])], - ]) - }) - }) - - describe('second radio button', () => { - beforeEach(async () => { - await wrapper.findAll('input[type="radio"]').at(1).setChecked() - }) - - it('emits update-radio-selected with index 1', () => { - expect(wrapper.emitted()['update-radio-selected']).toEqual([ - [expect.arrayContaining([1])], - ]) - }) - }) - - describe('third radio button', () => { - beforeEach(async () => { - await wrapper.findAll('input[type="radio"]').at(2).setChecked() - }) - - it('emits update-radio-selected with index 2', () => { - expect(wrapper.emitted()['update-radio-selected']).toEqual([ - [expect.arrayContaining([2])], - ]) - }) - }) - }) - describe('with single creation', () => { beforeEach(async () => { jest.clearAllMocks() @@ -153,17 +100,17 @@ describe('CreationFormular', () => { item: { email: 'benjamin@bluemchen.de' }, }) await wrapper.findAll('input[type="radio"]').at(1).setChecked() - await wrapper.find('textarea').setValue('Test create coins') await wrapper.find('input[type="number"]').setValue(90) }) describe('first radio button', () => { beforeEach(async () => { await wrapper.findAll('input[type="radio"]').at(0).setChecked() + await wrapper.find('textarea').setValue('Test create coins') }) it('sets rangeMax to 200', () => { - expect(wrapper.vm.rangeMax).toBe(400) + expect(wrapper.vm.rangeMax).toBe(200) }) describe('sendForm', () => { @@ -177,7 +124,7 @@ describe('CreationFormular', () => { mutation: createPendingCreation, variables: { email: 'benjamin@bluemchen.de', - creationDate: 'YYYY-MM-01', + creationDate: getCreationDate(2), amount: 90, memo: 'Test create coins', moderator: 0, @@ -185,9 +132,30 @@ describe('CreationFormular', () => { }), ) }) + + it('emits update-user-data', () => { + expect(wrapper.emitted('update-user-data')).toEqual([ + [{ email: 'benjamin@bluemchen.de' }, [0, 0, 0]], + ]) + }) + + it('toasts a success message', () => { + expect(toastedSuccessMock).toBeCalledWith([ + 'creation_form.toasted', + { email: 'benjamin@bluemchen.de', value: '90' }, + ]) + }) + + it('updates open creations in store', () => { + expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 1) + }) + + it('resets the form data', () => { + expect(wrapper.vm.value).toBe(0) + }) }) - describe('sendForm', () => { + describe('sendForm with server error', () => { beforeEach(async () => { apolloMutateMock.mockRejectedValueOnce({ message: 'Ouch!' }) await wrapper.find('.test-submit').trigger('click') @@ -373,9 +341,18 @@ describe('CreationFormular', () => { }) }) - describe('with mass creation', () => { + describe('mass creation with success', () => { beforeEach(async () => { jest.clearAllMocks() + apolloMutateMock.mockResolvedValue({ + data: { + createPendingCreations: { + success: true, + successfulCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'], + failedCreation: [], + }, + }, + }) await wrapper.setProps({ type: 'massCreation', creation: [200, 400, 600], @@ -395,14 +372,14 @@ describe('CreationFormular', () => { pendingCreations: [ { email: 'bob@baumeister.de', - creationDate: 'YYYY-MM-01', + creationDate: getCreationDate(1), amount: 200, memo: 'Test mass create coins', moderator: 0, }, { email: 'bibi@bloxberg.de', - creationDate: 'YYYY-MM-01', + creationDate: getCreationDate(1), amount: 200, memo: 'Test mass create coins', moderator: 0, @@ -412,6 +389,73 @@ describe('CreationFormular', () => { }), ) }) + + it('updates open creations in store', () => { + expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 2) + }) + + it('emits remove-all-bookmark', () => { + expect(wrapper.emitted('remove-all-bookmark')).toBeTruthy() + }) + }) + + describe('mass creation with success but all failed', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloMutateMock.mockResolvedValue({ + data: { + createPendingCreations: { + success: true, + successfulCreation: [], + failedCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'], + }, + }, + }) + await wrapper.setProps({ + type: 'massCreation', + creation: [200, 400, 600], + items: [{ email: 'bob@baumeister.de' }, { email: 'bibi@bloxberg.de' }], + }) + await wrapper.findAll('input[type="radio"]').at(1).setChecked() + await wrapper.find('textarea').setValue('Test mass create coins') + await wrapper.find('input[type="number"]').setValue(200) + await wrapper.find('.test-submit').trigger('click') + }) + + it('updates open creations in store', () => { + expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 0) + }) + + it('toasts two errors', () => { + expect(toastedErrorMock).toBeCalledWith( + 'Could not created PendingCreation for bob@baumeister.de', + ) + expect(toastedErrorMock).toBeCalledWith( + 'Could not created PendingCreation for bibi@bloxberg.de', + ) + }) + }) + + describe('mass creation with error', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloMutateMock.mockRejectedValue({ + message: 'Oh no!', + }) + await wrapper.setProps({ + type: 'massCreation', + creation: [200, 400, 600], + items: [{ email: 'bob@baumeister.de' }, { email: 'bibi@bloxberg.de' }], + }) + await wrapper.findAll('input[type="radio"]').at(1).setChecked() + await wrapper.find('textarea').setValue('Test mass create coins') + await wrapper.find('input[type="number"]').setValue(200) + await wrapper.find('.test-submit').trigger('click') + }) + + it('toasts an error message', () => { + expect(toastedErrorMock).toBeCalledWith('Oh no!') + }) }) }) }) diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index 3c8c914e2..34df13e11 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -7,51 +7,15 @@ - - - - - - - - - - - - - - - + - -
+
@@ -62,7 +26,6 @@ :max="rangeMax" > -
-
+
@@ -100,18 +63,17 @@ variant="success" class="test-submit" @click="submitCreation" - :disabled="radioSelected === '' || value <= 0 || text.length < 10" + :disabled="selected === '' || value <= 0 || text.length < 10" > {{ $t('creation_form.update_creation') }} - {{ $t('creation_form.submit_creation') }} @@ -123,11 +85,12 @@
diff --git a/admin/src/components/EditCreationFormular.spec.js b/admin/src/components/EditCreationFormular.spec.js index ed0f412ba..84d3e26d3 100644 --- a/admin/src/components/EditCreationFormular.spec.js +++ b/admin/src/components/EditCreationFormular.spec.js @@ -7,8 +7,9 @@ const apolloMutateMock = jest.fn().mockResolvedValue({ data: { updatePendingCreation: { creation: [0, 0, 0], + amount: 500, date: new Date(), - memo: 'qwertzuiopasdfghjkl', + memo: 'Test Schöpfung 2', moderator: 0, }, }, @@ -20,15 +21,9 @@ const toastedSuccessMock = jest.fn() const mocks = { $t: jest.fn((t) => t), - $moment: jest.fn(() => { - return { - format: jest.fn((m) => m), - subtract: jest.fn(() => { - return { - format: jest.fn((m) => m), - } - }), - } + $d: jest.fn((d) => { + const date = new Date(d) + return date.toISOString().split('T')[0] }), $apollo: { mutate: apolloMutateMock, @@ -48,12 +43,18 @@ const mocks = { }, } +const now = new Date(Date.now()) +const getCreationDate = (sub) => { + const date = sub === 0 ? now : new Date(now.getFullYear(), now.getMonth() - sub, 1, 0) + return date.toISOString().split('T')[0] +} + const propsData = { creation: [200, 400, 600], creationUserData: { memo: 'Test schöpfung 1', amount: 100, - date: '2021-12-01', + date: getCreationDate(0), }, item: { id: 0, @@ -82,196 +83,79 @@ describe('EditCreationFormular', () => { expect(wrapper.findAll('input[type="radio"]').length).toBe(3) }) - describe('with single creation', () => { + it('has the third radio button checked', () => { + expect(wrapper.findAll('input[type="radio"]').at(0).element.checked).toBeFalsy() + expect(wrapper.findAll('input[type="radio"]').at(1).element.checked).toBeFalsy() + expect(wrapper.findAll('input[type="radio"]').at(2).element.checked).toBeTruthy() + }) + + it('has rangeMax of 700', () => { + expect(wrapper.find('input[type="number"]').attributes('max')).toBe('700') + }) + + describe('change and save memo and value with success', () => { beforeEach(async () => { - jest.clearAllMocks() - await wrapper.setProps({ creation: [200, 400, 600] }) - await wrapper.setData({ rangeMin: 180 }) - await wrapper.setData({ text: 'Test create coins' }) - await wrapper.setData({ value: 90 }) + await wrapper.find('input[type="number"]').setValue(500) + await wrapper.find('textarea').setValue('Test Schöpfung 2') + await wrapper.find('.test-submit').trigger('click') }) - describe('first radio button', () => { - beforeEach(async () => { - await wrapper.findAll('input[type="radio"]').at(0).setChecked() - }) - - it('sets rangeMin to 0', () => { - expect(wrapper.vm.rangeMin).toBe(0) - }) - - it('sets rangeMax to 200', () => { - expect(wrapper.vm.rangeMax).toBe(200) - }) - - describe('sendForm', () => { - beforeEach(async () => { - await wrapper.find('.test-submit').trigger('click') - }) - - it('sends ... to apollo', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - variables: { - amount: 90, - creationDate: 'YYYY-MM-01', - email: 'bob@baumeister.de', - id: 0, - memo: 'Test create coins', - moderator: 0, - }, - }), - ) - }) - - it('emits update-user-data', () => { - expect(wrapper.emitted('update-user-data')).toBeTruthy() - expect(wrapper.emitted('update-user-data')).toEqual([ - [ - { - id: 0, - email: 'bob@baumeister.de', - }, - [0, 0, 0], - ], - ]) - }) - - it('toast success message', () => { - expect(toastedSuccessMock).toBeCalledWith('creation_form.toasted_update') - }) - - describe('sendForm with error', () => { - beforeEach(async () => { - jest.clearAllMocks() - apolloMutateMock.mockRejectedValue({ - message: 'Ouch!', - }) - wrapper = Wrapper() - await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] }) - await wrapper.setData({ text: 'Test create coins' }) - await wrapper.setData({ value: 90 }) - await wrapper.findAll('input[type="radio"]').at(0).setChecked() - await wrapper.setData({ rangeMin: 100 }) - await wrapper.find('.test-submit').trigger('click') - }) - - it('toast error message', () => { - expect(toastedErrorMock).toBeCalledWith('Ouch!') - }) - }) - }) + it('calls the API', () => { + expect(apolloMutateMock).toBeCalledWith( + expect.objectContaining({ + variables: { + id: 0, + email: 'bob@baumeister.de', + creationDate: getCreationDate(0), + amount: 500, + memo: 'Test Schöpfung 2', + moderator: 0, + }, + }), + ) }) - describe('second radio button', () => { - beforeEach(async () => { - await wrapper.findAll('input[type="radio"]').at(1).setChecked() - }) - - it('sets rangeMin to 0', () => { - expect(wrapper.vm.rangeMin).toBe(0) - }) - - it('sets rangeMax to 400', () => { - expect(wrapper.vm.rangeMax).toBe(400) - }) - - describe('sendForm', () => { - beforeEach(async () => { - await wrapper.find('.test-submit').trigger('click') - }) - - it('sends ... to apollo', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - variables: { - amount: 90, - creationDate: 'YYYY-MM-01', - email: 'bob@baumeister.de', - id: 0, - memo: 'Test create coins', - moderator: 0, - }, - }), - ) - }) - - describe('sendForm with error', () => { - beforeEach(async () => { - jest.clearAllMocks() - apolloMutateMock.mockRejectedValue({ - message: 'Ouch!', - }) - wrapper = Wrapper() - await wrapper.setProps({ creation: [200, 400, 600] }) - await wrapper.setData({ text: 'Test create coins' }) - await wrapper.setData({ value: 100 }) - await wrapper.findAll('input[type="radio"]').at(1).setChecked() - await wrapper.setData({ rangeMin: 180 }) - await wrapper.find('.test-submit').trigger('click') - }) - - it('toast error message', () => { - expect(toastedErrorMock).toBeCalledWith('Ouch!') - }) - }) - }) + it('emits update-user-data', () => { + expect(wrapper.emitted('update-user-data')).toEqual([ + [ + { + id: 0, + email: 'bob@baumeister.de', + }, + [0, 0, 0], + ], + ]) }) - describe('third radio button', () => { - beforeEach(async () => { - await wrapper.setData({ rangeMin: 180 }) - await wrapper.findAll('input[type="radio"]').at(2).setChecked() - }) + it('emits update-creation-data', () => { + expect(wrapper.emitted('update-creation-data')).toEqual([ + [ + { + amount: 500, + date: expect.any(Date), + memo: 'Test Schöpfung 2', + moderator: 0, + row: expect.any(Object), + }, + ], + ]) + }) - it('sets rangeMin to 180', () => { - expect(wrapper.vm.rangeMin).toBe(180) - }) + it('toasts a success message', () => { + expect(toastedSuccessMock).toBeCalledWith('creation_form.toasted_update') + }) + }) - it('sets rangeMax to 700', () => { - expect(wrapper.vm.rangeMax).toBe(700) - }) + describe('change and save memo and value with error', () => { + beforeEach(async () => { + apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) + await wrapper.find('input[type="number"]').setValue(500) + await wrapper.find('textarea').setValue('Test Schöpfung 2') + await wrapper.find('.test-submit').trigger('click') + }) - describe('sendForm with success', () => { - beforeEach(async () => { - await wrapper.find('.test-submit').trigger('click') - }) - - it('sends ... to apollo', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - variables: { - amount: 90, - creationDate: 'YYYY-MM-DD', - email: 'bob@baumeister.de', - id: 0, - memo: 'Test create coins', - moderator: 0, - }, - }), - ) - }) - }) - - describe('sendForm with error', () => { - beforeEach(async () => { - jest.clearAllMocks() - apolloMutateMock.mockRejectedValue({ - message: 'Ouch!', - }) - wrapper = Wrapper() - await wrapper.setProps({ creation: [200, 400, 600] }) - await wrapper.setData({ text: 'Test create coins' }) - await wrapper.setData({ value: 90 }) - await wrapper.findAll('input[type="radio"]').at(2).setChecked() - await wrapper.setData({ rangeMin: 180 }) - await wrapper.find('.test-submit').trigger('click') - }) - - it('toast error message', () => { - expect(toastedErrorMock).toBeCalledWith('Ouch!') - }) - }) + it('toasts an error message', () => { + expect(toastedErrorMock).toBeCalledWith('Oh no!') }) }) }) diff --git a/admin/src/components/EditCreationFormular.vue b/admin/src/components/EditCreationFormular.vue index 2fa45dd8e..650b00410 100644 --- a/admin/src/components/EditCreationFormular.vue +++ b/admin/src/components/EditCreationFormular.vue @@ -6,65 +6,14 @@
- - - - - - - - - - - - - - - + -
@@ -76,7 +25,6 @@ :max="rangeMax" > - {{ $t('creation_form.update_creation') }} @@ -126,8 +74,11 @@