diff --git a/admin/package.json b/admin/package.json index 3406c326a..521f34bfc 100644 --- a/admin/package.json +++ b/admin/package.json @@ -33,6 +33,7 @@ "bootstrap": "4.3.1", "bootstrap-vue": "^2.21.2", "core-js": "^3.6.5", + "date-fns": "^2.29.3", "dotenv-webpack": "^7.0.3", "express": "^4.17.1", "graphql": "^15.6.1", diff --git a/admin/src/components/ChangeUserRoleFormular.spec.js b/admin/src/components/ChangeUserRoleFormular.spec.js index 7f2154ecc..381d2ce43 100644 --- a/admin/src/components/ChangeUserRoleFormular.spec.js +++ b/admin/src/components/ChangeUserRoleFormular.spec.js @@ -28,6 +28,7 @@ const mocks = { let propsData let wrapper +let spy describe('ChangeUserRoleFormular', () => { const Wrapper = () => { @@ -70,12 +71,16 @@ describe('ChangeUserRoleFormular', () => { expect(wrapper.text()).toContain('userRole.notChangeYourSelf') }) - it('has role select disabled', () => { - expect(wrapper.find('select[disabled="disabled"]').exists()).toBe(true) + it('has no role select', () => { + expect(wrapper.find('select.role-select').exists()).toBe(false) + }) + + it('has no button', () => { + expect(wrapper.find('button.btn.btn-dange').exists()).toBe(false) }) }) - describe('change others role', () => { + describe("change other user's role", () => { let rolesToSelect describe('general', () => { @@ -106,19 +111,12 @@ describe('ChangeUserRoleFormular', () => { expect(wrapper.find('select.role-select[disabled="disabled"]').exists()).toBe(false) }) - describe('on API error', () => { - beforeEach(() => { - apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) - rolesToSelect.at(1).setSelected() - }) - - it('toasts an error message', () => { - expect(toastErrorSpy).toBeCalledWith('Oh no!') - }) + it('has "change_user_role" button', () => { + expect(wrapper.find('button.btn.btn-danger').text()).toBe('change_user_role') }) }) - describe('user is usual user', () => { + describe('user has role "usual user"', () => { beforeEach(() => { apolloMutateMock.mockResolvedValue({ data: { @@ -141,6 +139,10 @@ describe('ChangeUserRoleFormular', () => { describe('change select to', () => { describe('same role', () => { + it('has "change_user_role" button disabled', () => { + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(true) + }) + it('does not call the API', () => { rolesToSelect.at(0).setSelected() expect(apolloMutateMock).not.toHaveBeenCalled() @@ -152,39 +154,75 @@ describe('ChangeUserRoleFormular', () => { rolesToSelect.at(1).setSelected() }) - it('calls the API', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - mutation: setUserRole, - variables: { - userId: 1, - isAdmin: true, - }, - }), + it('has "change_user_role" button enabled', () => { + expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true) + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe( + false, ) }) - it('emits "updateIsAdmin"', () => { - expect(wrapper.emitted('updateIsAdmin')).toEqual( - expect.arrayContaining([ - expect.arrayContaining([ - { - userId: 1, - isAdmin: expect.any(Date), - }, - ]), - ]), - ) - }) + describe('clicking the "change_user_role" button', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + spy.mockImplementation(() => Promise.resolve(true)) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) - it('toasts success message', () => { - expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + it('calls the modal', () => { + expect(wrapper.emitted('showModal')) + expect(spy).toHaveBeenCalled() + }) + + describe('confirm role change with success', () => { + it('calls the API', () => { + expect(apolloMutateMock).toBeCalledWith( + expect.objectContaining({ + mutation: setUserRole, + variables: { + userId: 1, + isAdmin: true, + }, + }), + ) + }) + + it('emits "updateIsAdmin"', () => { + expect(wrapper.emitted('updateIsAdmin')).toEqual( + expect.arrayContaining([ + expect.arrayContaining([ + { + userId: 1, + isAdmin: expect.any(Date), + }, + ]), + ]), + ) + }) + + it('toasts success message', () => { + expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + }) + }) + + describe('confirm role change with error', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) + + it('toasts an error message', () => { + expect(toastErrorSpy).toBeCalledWith('Oh no!') + }) + }) }) }) }) }) - describe('user is admin', () => { + describe('user has role "admin"', () => { beforeEach(() => { apolloMutateMock.mockResolvedValue({ data: { @@ -207,6 +245,10 @@ describe('ChangeUserRoleFormular', () => { describe('change select to', () => { describe('same role', () => { + it('has "change_user_role" button disabled', () => { + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(true) + }) + it('does not call the API', () => { rolesToSelect.at(1).setSelected() expect(apolloMutateMock).not.toHaveBeenCalled() @@ -218,33 +260,69 @@ describe('ChangeUserRoleFormular', () => { rolesToSelect.at(0).setSelected() }) - it('calls the API', () => { - expect(apolloMutateMock).toBeCalledWith( - expect.objectContaining({ - mutation: setUserRole, - variables: { - userId: 1, - isAdmin: false, - }, - }), + it('has "change_user_role" button enabled', () => { + expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true) + expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe( + false, ) }) - it('emits "updateIsAdmin"', () => { - expect(wrapper.emitted('updateIsAdmin')).toEqual( - expect.arrayContaining([ - expect.arrayContaining([ - { - userId: 1, - isAdmin: null, - }, - ]), - ]), - ) - }) + describe('clicking the "change_user_role" button', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + spy.mockImplementation(() => Promise.resolve(true)) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) - it('toasts success message', () => { - expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + it('calls the modal', () => { + expect(wrapper.emitted('showModal')) + expect(spy).toHaveBeenCalled() + }) + + describe('confirm role change with success', () => { + it('calls the API', () => { + expect(apolloMutateMock).toBeCalledWith( + expect.objectContaining({ + mutation: setUserRole, + variables: { + userId: 1, + isAdmin: false, + }, + }), + ) + }) + + it('emits "updateIsAdmin"', () => { + expect(wrapper.emitted('updateIsAdmin')).toEqual( + expect.arrayContaining([ + expect.arrayContaining([ + { + userId: 1, + isAdmin: null, + }, + ]), + ]), + ) + }) + + it('toasts success message', () => { + expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo') + }) + }) + + describe('confirm role change with error', () => { + beforeEach(async () => { + spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') + apolloMutateMock.mockRejectedValue({ message: 'Oh no!' }) + await wrapper.find('button').trigger('click') + await wrapper.vm.$nextTick() + }) + + it('toasts an error message', () => { + expect(toastErrorSpy).toBeCalledWith('Oh no!') + }) + }) }) }) }) diff --git a/admin/src/components/ChangeUserRoleFormular.vue b/admin/src/components/ChangeUserRoleFormular.vue index 1217ce7f0..677a12f56 100644 --- a/admin/src/components/ChangeUserRoleFormular.vue +++ b/admin/src/components/ChangeUserRoleFormular.vue @@ -4,19 +4,23 @@
{{ $t('userRole.notChangeYourSelf') }}
-
+
- + +
+ + {{ $t('change_user_role') }} + +
- diff --git a/admin/src/components/NavBar.spec.js b/admin/src/components/NavBar.spec.js index 1927f258c..6a4a69959 100644 --- a/admin/src/components/NavBar.spec.js +++ b/admin/src/components/NavBar.spec.js @@ -62,8 +62,12 @@ describe('NavBar', () => { ) }) + it('has a link to /federation', () => { + expect(wrapper.findAll('.nav-item').at(3).find('a').attributes('href')).toBe('/federation') + }) + it('has a link to /statistic', () => { - expect(wrapper.findAll('.nav-item').at(3).find('a').attributes('href')).toBe('/statistic') + expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe('/statistic') }) }) @@ -72,7 +76,7 @@ describe('NavBar', () => { beforeEach(async () => { delete window.location window.location = '' - await wrapper.findAll('.nav-item').at(4).find('a').trigger('click') + await wrapper.findAll('.nav-item').at(5).find('a').trigger('click') }) afterEach(() => { @@ -97,7 +101,7 @@ describe('NavBar', () => { window.location = { assign: windowLocationMock, } - await wrapper.findAll('.nav-item').at(5).find('a').trigger('click') + await wrapper.findAll('.nav-item').at(6).find('a').trigger('click') }) afterEach(() => { diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index dae4bba91..2efeda048 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -1,6 +1,6 @@ diff --git a/frontend/src/components/GddTransactionList.spec.js b/frontend/src/components/GddTransactionList.spec.js index 7473c11e0..b1cdf9eb9 100644 --- a/frontend/src/components/GddTransactionList.spec.js +++ b/frontend/src/components/GddTransactionList.spec.js @@ -93,8 +93,9 @@ describe('GddTransactionList', () => { { id: -1, typeId: 'DECAY', - amount: '-0.16778637075575395772595', - balance: '31.59320453982945549519405', + amount: '-0.16', + balance: '31.59', + previousBalance: '31.75', balanceDate: '2022-03-03T08:54:54', memo: '', linkedUser: null, @@ -110,6 +111,7 @@ describe('GddTransactionList', () => { typeId: 'SEND', amount: '1', balance: '31.76099091058520945292', + previousBalance: '30.76', balanceDate: '2022-02-28T13:55:47', memo: 'Um den Kessel schlingt den Reihn, Werft die Eingeweid‘ hinein. Kröte du, die Nacht und Tag Unterm kalten Steine lag,', @@ -129,6 +131,7 @@ describe('GddTransactionList', () => { typeId: 'RECEIVE', amount: '10', balance: '10', + previousBalance: '31.75', balanceDate: '2022-02-23T10:55:30', memo: 'Monatlanges Gift sog ein, In den Topf zuerst hinein… (William Shakespeare, Die Hexen aus Macbeth)', @@ -148,6 +151,7 @@ describe('GddTransactionList', () => { typeId: 'CREATION', amount: '1000', balance: '32.96482231613347376132', + previousBalance: '31.75', balanceDate: '2022-02-25T07:29:26', memo: 'Jammern hilft nichts, sondern ich kann selber meinen Teil dazu beitragen.', linkedUser: { @@ -414,6 +418,7 @@ describe('GddTransactionList', () => { return { amount: '3.14', balanceDate: '2021-04-29T17:26:40+00:00', + previousBalance: '31.75', decay: { decay: '-477.01', start: '2021-05-13T17:46:31.000Z', diff --git a/frontend/src/components/GddTransactionList.vue b/frontend/src/components/GddTransactionList.vue index deed0dedb..092ff6a34 100644 --- a/frontend/src/components/GddTransactionList.vue +++ b/frontend/src/components/GddTransactionList.vue @@ -19,10 +19,7 @@ class="pointer bg-white appBoxShadow gradido-border-radius px-4 pt-2 test-list-group-item" > @@ -34,27 +31,15 @@ class="pointer mb-3 bg-white appBoxShadow gradido-border-radius p-3 test-list-group-item" >