From da28f1f364f96eb4140c3877293799330734ba73 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 16 Jun 2021 13:40:27 +0200 Subject: [PATCH 01/71] setuo password component --- .../src/components/Inputs/InputPassword.vue | 63 +++++++++++++++++++ frontend/src/locales/de.json | 3 +- frontend/src/locales/en.json | 3 +- frontend/src/views/Pages/Login.vue | 52 ++++----------- 4 files changed, 80 insertions(+), 41 deletions(-) create mode 100644 frontend/src/components/Inputs/InputPassword.vue diff --git a/frontend/src/components/Inputs/InputPassword.vue b/frontend/src/components/Inputs/InputPassword.vue new file mode 100644 index 000000000..638eb6eb3 --- /dev/null +++ b/frontend/src/components/Inputs/InputPassword.vue @@ -0,0 +1,63 @@ + + diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 8554996bb..a1cdf985b 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -64,7 +64,8 @@ "change_username_info": "Einmal gespeichert, kann der Username ncht mehr geändert werden!" }, "error": { - "error":"Fehler" + "error":"Fehler", + "no-account": "Leider konnten wir keinen Account finden mit diesen Daten!" }, "transaction":{ "show_all":"Alle {count} Transaktionen ansehen", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 7b97c2240..6e39a04b7 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -64,7 +64,8 @@ "change_username_info": "Once saved, the username cannot be changed again!" }, "error": { - "error":"Error" + "error":"Error", + "no-account": "Unfortunately we could not find an account to the given data!" }, "transaction":{ "show_all":"View all {count} transactions.", diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index 4619dddf2..d08171c1f 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -46,52 +46,25 @@ - - - - - - - - - - - - - {{ validationContext.errors[0] }} - - - + - Leider konnten wir keinen Account finden mit diesen Daten! + {{ $t('error.no-account') }} -
+
{{ $t('login') }}
@@ -118,9 +91,13 @@ + diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index 25c40df5a..2d4ce2345 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -13,7 +13,6 @@
- @@ -22,47 +21,14 @@
{{ $t('login') }}
- - - - - - - - - {{ validationContext.errors[0] }} - - - - + + + - - - - - - - {{ $t('error.no-account') }} - - - - -
{{ $t('login') }}
@@ -91,31 +57,26 @@ import loginAPI from '../../apis/loginAPI' import CONFIG from '../../config' import InputPassword from '../../components/Inputs/InputPassword' +import InputEmail from '../../components/Inputs/InputEmail' export default { name: 'login', components: { InputPassword, + InputEmail, }, data() { return { form: { email: '', password: '', - // rememberMe: false }, - loginfail: false, allowRegister: CONFIG.ALLOW_REGISTER, passwordVisible: false, } }, methods: { - getValidationState({ dirty, validated, valid = null }) { - return dirty || validated ? valid : null - }, async onSubmit() { - // error info ausschalten - this.loginfail = false const loader = this.$loading.show({ container: this.$refs.submitButton, }) @@ -129,7 +90,7 @@ export default { loader.hide() } else { loader.hide() - this.loginfail = true + this.$toast.error(this.$t('error.no-account')) } }, }, From 4a68dd3c7af9100ad1a9fabda171fc5477d918a8 Mon Sep 17 00:00:00 2001 From: Dario Rekowski on RockPI Date: Tue, 29 Jun 2021 09:56:23 +0000 Subject: [PATCH 11/71] decay only with first page, ensure that the limit is kept --- .../src/Controller/AppRequestsController.php | 15 +++++++++++++-- .../src/Model/Table/TransactionsTable.php | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/community_server/src/Controller/AppRequestsController.php b/community_server/src/Controller/AppRequestsController.php index ff3314e94..15c68cece 100644 --- a/community_server/src/Controller/AppRequestsController.php +++ b/community_server/src/Controller/AppRequestsController.php @@ -333,16 +333,27 @@ class AppRequestsController extends AppController $this->addAdminError('StateBalancesController', 'overview', $gdtEntries, $user['id'] ? $user['id'] : 0); } + $limit = $count; + $offset = 0; + if($page == 1) { + $limit--; + } else { + $offset = (( $page - 1 ) * $count) - 1; + } $stateUserTransactionsQuery = $stateUserTransactionsTable ->find() ->where(['state_user_id' => $user['id']]) ->order(['balance_date' => $orderDirection]) ->contain([]) - ->limit($count) - ->page($page) + ->limit($limit) + //->page($page) + ->offset($offset) ; $decay = true; + if($page > 1) { + $decay = false; + } $transactions = []; $transactions_from_db = $stateUserTransactionsQuery->toArray(); diff --git a/community_server/src/Model/Table/TransactionsTable.php b/community_server/src/Model/Table/TransactionsTable.php index 61e14d231..8fcd81489 100644 --- a/community_server/src/Model/Table/TransactionsTable.php +++ b/community_server/src/Model/Table/TransactionsTable.php @@ -185,7 +185,7 @@ class TransactionsTable extends Table if($i > 0 ) { $prev = $stateUserTransactions[$i-1]; } - if($prev && $decay == true) + if($prev) { if($prev->balance > 0) { $current = $su_transaction; @@ -252,7 +252,7 @@ class TransactionsTable extends Table $final_transactions[] = $final_transaction; - if($i == $stateUserTransactionsCount-1 && $decay == true) { + if($i == $stateUserTransactionsCount-1 && $decay) { $now = new FrozenTime(); $calculated_decay = $stateBalancesTable->calculateDecay( $su_transaction->balance, From 221f9ec2ee2d1252f14f285b006c8da66f1ae695 Mon Sep 17 00:00:00 2001 From: Dario Rekowski on RockPI Date: Tue, 29 Jun 2021 09:56:32 +0000 Subject: [PATCH 12/71] update test --- .../TestCase/Controller/AppRequestControllerTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/community_server/tests/TestCase/Controller/AppRequestControllerTest.php b/community_server/tests/TestCase/Controller/AppRequestControllerTest.php index 6d179845f..5aeb64d8b 100644 --- a/community_server/tests/TestCase/Controller/AppRequestControllerTest.php +++ b/community_server/tests/TestCase/Controller/AppRequestControllerTest.php @@ -205,6 +205,12 @@ class AppRequestControllerTest extends TestCase "transaction_id": 7, "date": "2021-04-14T09:02:28+00:00", "memo": "test time 3", + "decay": { + "balance": 6, + "decay_duration": "0 days, 00 hours, 00 minutes, 28 seconds", + "decay_start": 1618390920, + "decay_end": 1618390948 + }, "balance": 100000, "type": "receive", "pubkey": "0000000000000000000000000000000000000000000000000000000000000000", @@ -231,6 +237,12 @@ class AppRequestControllerTest extends TestCase "transaction_id": 9, "date": "2021-04-14T09:31:28+00:00", "memo": "test login crash", + "decay": { + "balance": 33, + "decay_duration": "0 days, 00 hours, 02 minutes, 42 seconds", + "decay_start": 1618392526, + "decay_end": 1618392688 + }, "balance": 100000, "type": "receive", "pubkey": "0000000000000000000000000000000000000000000000000000000000000000", From 789808ea408997ab66fd9954fa7dd4ee5fc58049 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 29 Jun 2021 14:02:09 +0200 Subject: [PATCH 13/71] Complete test for login page --- frontend/src/components/Inputs/InputEmail.vue | 2 +- frontend/src/views/Pages/Login.spec.js | 119 ++++++++++++++++-- 2 files changed, 110 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/Inputs/InputEmail.vue b/frontend/src/components/Inputs/InputEmail.vue index adcd66345..41338fd8c 100644 --- a/frontend/src/components/Inputs/InputEmail.vue +++ b/frontend/src/components/Inputs/InputEmail.vue @@ -37,7 +37,7 @@ export default { } }, }, - name: { type: String, default: 'email' }, + name: { type: String, default: 'Email' }, label: { type: String, default: 'Email' }, placeholder: { type: String, default: 'Email' }, value: { required: true, type: String }, diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index 0d94840b0..a4ff79bed 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -1,10 +1,37 @@ import { mount, RouterLinkStub } from '@vue/test-utils' import flushPromises from 'flush-promises' - +import loginAPI from '../../apis/loginAPI' import Login from './Login' +jest.mock('../../apis/loginAPI') + const localVue = global.localVue +const mockLoginCall = jest.fn() +mockLoginCall.mockReturnValue({ + success: true, + result: { + data: { + session_id: 1, + user: { + name: 'Peter Lustig', + }, + }, + }, +}) + +loginAPI.login = mockLoginCall + +const toastErrorMock = jest.fn() +const mockStoreDispach = jest.fn() +const mockRouterPush = jest.fn() +const spinnerHideMock = jest.fn() +const spinnerMock = jest.fn(() => { + return { + hide: spinnerHideMock, + } +}) + describe('Login', () => { let wrapper @@ -13,6 +40,18 @@ describe('Login', () => { locale: 'en', }, $t: jest.fn((t) => t), + $store: { + dispatch: mockStoreDispach, + }, + $loading: { + show: spinnerMock, + }, + $router: { + push: mockRouterPush, + }, + $toast: { + error: toastErrorMock, + }, } const stubs = { @@ -76,16 +115,76 @@ describe('Login', () => { it('has a Submit button', () => { expect(wrapper.find('button[type="submit"]').exists()).toBeTruthy() }) - - it('shows a warning when no valid Email is entered', async () => { - wrapper.find('input[placeholder="Email"]').setValue('no_valid@Email') - await flushPromises() - await expect(wrapper.find('.invalid-feedback').text()).toEqual( - 'The Email field must be a valid email', - ) - }) }) - // to do: test submit button + describe('submit', () => { + describe('no data', () => { + it('displays a message that Email is required', async () => { + await wrapper.find('form').trigger('submit') + await flushPromises() + expect(wrapper.findAll('div.invalid-feedback').at(0).text()).toBe( + 'The Email field is required', + ) + }) + + it('displays a message that password is required', async () => { + await wrapper.find('form').trigger('submit') + await flushPromises() + expect(wrapper.findAll('div.invalid-feedback').at(1).text()).toBe( + 'The password field is required', + ) + }) + }) + + describe('valid data', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.find('input[placeholder="Email"]').setValue('user@example.org') + await wrapper.find('input[placeholder="form.password"]').setValue('1234') + await flushPromises() + await wrapper.find('form').trigger('submit') + await flushPromises() + }) + + it('calls the API with the given data', () => { + expect(mockLoginCall).toBeCalledWith('user@example.org', '1234') + }) + + it('creates a spinner', () => { + expect(spinnerMock).toBeCalled() + }) + + describe('login success', () => { + it('dispatches server response to store', () => { + expect(mockStoreDispach).toBeCalledWith('login', { + sessionId: 1, + user: { name: 'Peter Lustig' }, + }) + }) + + it('redirects to overview page', () => { + expect(mockRouterPush).toBeCalledWith('/overview') + }) + + it('hides the spinner', () => { + expect(spinnerHideMock).toBeCalled() + }) + }) + + describe('login fails', () => { + beforeEach(() => { + mockLoginCall.mockReturnValue({ success: false }) + }) + + it('hides the spinner', () => { + expect(spinnerHideMock).toBeCalled() + }) + + it('toasts an error message', () => { + expect(toastErrorMock).toBeCalledWith('error.no-account') + }) + }) + }) + }) }) }) From d3382620fa551ae2f2587bba404565cfecbead37 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 29 Jun 2021 14:09:34 +0200 Subject: [PATCH 14/71] frontend coverage to 33% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 14b507354..329b1dd60 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -212,7 +212,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 31 + min_coverage: 33 token: ${{ github.token }} ############################################################################## From 8dfb7d16dd255418c1a25f04bf14a384dcddf69d Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 29 Jun 2021 12:30:40 +0200 Subject: [PATCH 15/71] decay in transactionlist per transaction --- .../AccountOverview/GddTransactionList.vue | 66 ++++++++----------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue index 55f03f9e2..5e11fcce1 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue @@ -1,12 +1,12 @@ - From bcf24d9a413f3e8ed637e8dbbea6d4f4a20ce0dd Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 1 Jul 2021 13:20:37 +0200 Subject: [PATCH 22/71] component for password confirmation --- .../Inputs/InputPasswordConfirmation.spec.js | 79 +++++++++++++++++++ .../Inputs/InputPasswordConfirmation.vue | 68 ++++++++++++++++ .../UserProfile/UserCard_FormUserPasswort.vue | 42 +++------- 3 files changed, 156 insertions(+), 33 deletions(-) create mode 100644 frontend/src/components/Inputs/InputPasswordConfirmation.spec.js create mode 100644 frontend/src/components/Inputs/InputPasswordConfirmation.vue diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js b/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js new file mode 100644 index 000000000..ef3b5d64e --- /dev/null +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js @@ -0,0 +1,79 @@ +import { mount } from '@vue/test-utils' +import { extend } from 'vee-validate' + +import InputPasswordConfirmation from './InputPasswordConfirmation' + +const rules = [ + 'containsLowercaseCharacter', + 'containsUppercaseCharacter', + 'containsNumericCharacter', + 'atLeastEightCharactera', + 'samePassword', +] + +rules.forEach((rule) => { + extend(rule, { + validate(value) { + return true + }, + }) +}) + +const localVue = global.localVue + +describe('InputPasswordConfirmation', () => { + let wrapper + + const propsData = { + value: { + password: '', + passwordRepeat: '', + }, + } + + const mocks = { + $t: jest.fn((t) => t), + } + + const Wrapper = () => { + return mount(InputPasswordConfirmation, { localVue, propsData, mocks }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has two input fields', () => { + expect(wrapper.findAll('input')).toHaveLength(2) + }) + + describe('input values ', () => { + it('emits input with new value for first input field', async () => { + await wrapper.findAll('input').at(0).setValue('1234') + expect(wrapper.emitted('input')).toBeTruthy() + expect(wrapper.emitted('input')).toEqual([ + [ + { + password: '1234', + passwordRepeat: '', + }, + ], + ]) + }) + + it('emits input with new value for second input field', async () => { + await wrapper.findAll('input').at(1).setValue('1234') + expect(wrapper.emitted('input')).toBeTruthy() + expect(wrapper.emitted('input')).toEqual([ + [ + { + password: '', + passwordRepeat: '1234', + }, + ], + ]) + }) + }) + }) +}) diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.vue b/frontend/src/components/Inputs/InputPasswordConfirmation.vue new file mode 100644 index 000000000..08efaccfd --- /dev/null +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.vue @@ -0,0 +1,68 @@ + + diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue index ba49662fd..00cacfd21 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue @@ -28,36 +28,8 @@ >
- - - - - - - - - - - + +
@@ -75,11 +47,13 @@ From 83e07be898635f88c8bf83f02f85b9c0d1b5b4fd Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 2 Jul 2021 17:27:04 +0200 Subject: [PATCH 29/71] decay information component --- frontend/src/components/DecayInformation.vue | 19 ++ .../src/views/Layout/DashboardLayout_gdd.vue | 2 +- .../AccountOverview/GddTransactionList.vue | 221 ++++++++++-------- 3 files changed, 139 insertions(+), 103 deletions(-) create mode 100644 frontend/src/components/DecayInformation.vue diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue new file mode 100644 index 000000000..5a5e8306d --- /dev/null +++ b/frontend/src/components/DecayInformation.vue @@ -0,0 +1,19 @@ + + diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.vue b/frontend/src/views/Layout/DashboardLayout_gdd.vue index 14456605b..517773892 100755 --- a/frontend/src/views/Layout/DashboardLayout_gdd.vue +++ b/frontend/src/views/Layout/DashboardLayout_gdd.vue @@ -128,7 +128,7 @@ export default { if (result.success) { this.GdtBalance = Number(result.result.data.gdtSum) this.transactions = result.result.data.transactions - console.log("this.transactions => ", this.transactions[1].decay.decay_start) + console.log('this.transactions => ', this.transactions[1].decay.decay_start) this.balance = Number(result.result.data.decay) this.bookedBalance = Number(result.result.data.balance) this.transactionCount = result.result.data.count diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue index e3c2252bd..fdced417d 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue @@ -1,12 +1,12 @@ From b7b4b8116c9a56bcfdf1d2c110acacd23d2e6462 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 5 Jul 2021 20:53:04 +0200 Subject: [PATCH 30/71] decay show moments duration --- frontend/src/components/DecayInformation.vue | 59 ++++++++++++++++++- frontend/src/locales/de.json | 2 + .../src/views/Layout/DashboardLayout_gdd.vue | 1 - .../AccountOverview/GddTransactionList.vue | 33 ++--------- 4 files changed, 63 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue index 5a5e8306d..4bd5d31be 100644 --- a/frontend/src/components/DecayInformation.vue +++ b/frontend/src/components/DecayInformation.vue @@ -1,5 +1,42 @@ diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 4d85269c5..3c8098346 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -19,6 +19,8 @@ "en": "English" }, "decay": "Vergänglichkeit", + "resieve": "", + "form": { "cancel": "Abbrechen", "reset": "Zurücksetzen", diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.vue b/frontend/src/views/Layout/DashboardLayout_gdd.vue index 517773892..9990b91f2 100755 --- a/frontend/src/views/Layout/DashboardLayout_gdd.vue +++ b/frontend/src/views/Layout/DashboardLayout_gdd.vue @@ -128,7 +128,6 @@ export default { if (result.success) { this.GdtBalance = Number(result.result.data.gdtSum) this.transactions = result.result.data.transactions - console.log('this.transactions => ', this.transactions[1].decay.decay_start) this.balance = Number(result.result.data.decay) this.bookedBalance = Number(result.result.data.balance) this.transactionCount = result.result.data.count diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue index fdced417d..be0ccf87d 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue @@ -18,16 +18,15 @@ {{ item.name ? item.name : $t('decay') }}
{{ $d($moment(item.date), 'long') }}
-

{{ getTransaction(item.transaction_id) }} GDD

-

{{ getTransaction(item.transaction_id).decay }} GDD

+
-
+
i
- +
@@ -42,7 +41,7 @@ {{ $d($moment(item.date), 'long') }}
-
an:
+
{{ item.type === 'receive' ? 'von:' : 'an:' }}
{{ item.name }}
@@ -51,31 +50,9 @@ }}
{{ item.memo }}
-
- Seit deiner letzten Transaction sind -
- -
- - {{ - getTransaction(item.transaction_id).decay - ? getTransaction(item.transaction_id).decay.balance - : 'missing' - }} - -
{{}} vergangen.
-
- + - - - {{ $t('transaction.more') }} - - - {{ item }} -
From c7905adb9e0615ff74c608fa8a0504f5ee101e9f Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 10:31:27 +0200 Subject: [PATCH 31/71] complete tests for Change Username --- frontend/src/views/Pages/Login.spec.js | 2 +- .../UserProfile/UserCard_FormUsername.spec.js | 42 ++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index a4ff79bed..2339cd341 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -131,7 +131,7 @@ describe('Login', () => { await wrapper.find('form').trigger('submit') await flushPromises() expect(wrapper.findAll('div.invalid-feedback').at(1).text()).toBe( - 'The password field is required', + 'The form.password field is required', ) }) }) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js index b1d705952..48bbe6b70 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js @@ -24,6 +24,10 @@ const mockAPIcall = jest.fn((args) => { return { success: true } }) +const toastErrorMock = jest.fn() +const toastSuccessMock = jest.fn() +const storeCommitMock = jest.fn() + loginAPI.changeUsernameProfile = mockAPIcall describe('UserCard_FormUsername', () => { @@ -37,10 +41,11 @@ describe('UserCard_FormUsername', () => { email: 'user@example.org', username: '', }, - commit: jest.fn(), + commit: storeCommitMock, }, $toast: { - success: jest.fn(), + success: toastSuccessMock, + error: toastErrorMock, }, } @@ -111,10 +116,43 @@ describe('UserCard_FormUsername', () => { expect(wrapper.find('div.display-username').text()).toEqual('@username') }) + it('commits the username to the store', () => { + expect(storeCommitMock).toBeCalledWith('username', 'username') + }) + + it('toasts an success message', () => { + expect(toastSuccessMock).toBeCalledWith('site.profil.user-data.change-success') + }) + it('has no edit button anymore', () => { expect(wrapper.find('svg.bi-pencil').exists()).toBeFalsy() }) }) + + describe('submit retruns error', () => { + beforeEach(async () => { + jest.clearAllMocks() + mockAPIcall.mockReturnValue({ + success: false, + result: { message: 'Error' }, + }) + await wrapper.find('input[placeholder="Username"]').setValue('username') + await wrapper.find('form').trigger('submit') + await flushPromises() + }) + + it('calls the loginAPI', () => { + expect(mockAPIcall).toHaveBeenCalledWith(1, 'user@example.org', 'username') + }) + + it('toasts an error message', () => { + expect(toastErrorMock).toBeCalledWith('Error') + }) + + it('renders an empty username', () => { + expect(wrapper.find('div.display-username').text()).toEqual('@') + }) + }) }) }) }) From e8a1f7034f6016b4d48696d7c15e62de39255f41 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 11:21:55 +0200 Subject: [PATCH 32/71] Tests for Edit User Data --- .../UserProfile/UserCard_FormUserData.spec.js | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js new file mode 100644 index 000000000..55d62bb05 --- /dev/null +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js @@ -0,0 +1,169 @@ +import { mount } from '@vue/test-utils' +import UserCardFormUserData from './UserCard_FormUserData' +import loginAPI from '../../../apis/loginAPI' +import flushPromises from 'flush-promises' + +jest.mock('../../../apis/loginAPI') + +const localVue = global.localVue + +const mockAPIcall = jest.fn((args) => { + return { success: true } +}) + +const toastErrorMock = jest.fn() +const toastSuccessMock = jest.fn() +const storeCommitMock = jest.fn() + +loginAPI.updateUserInfos = mockAPIcall + +describe('UserCard_FormUsername', () => { + let wrapper + + const mocks = { + $t: jest.fn((t) => t), + $store: { + state: { + sessionId: 1, + email: 'user@example.org', + firstName: 'Peter', + lastName: 'Lustig', + description: '', + }, + commit: storeCommitMock, + }, + $toast: { + success: toastSuccessMock, + error: toastErrorMock, + }, + } + + const Wrapper = () => { + return mount(UserCardFormUserData, { localVue, mocks }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders the component', () => { + expect(wrapper.find('div#userdata_form').exists()).toBeTruthy() + }) + + it('has an edit icon', () => { + expect(wrapper.find('svg.bi-pencil').exists()).toBeTruthy() + }) + + it('renders the first name', () => { + expect(wrapper.findAll('div.col').at(2).text()).toBe('Peter') + }) + + it('renders the last name', () => { + expect(wrapper.findAll('div.col').at(4).text()).toBe('Lustig') + }) + + it('renders the description', () => { + expect(wrapper.findAll('div.col').at(6).text()).toBe('') + }) + + describe('edit user data', () => { + beforeEach(async () => { + await wrapper.find('svg.bi-pencil').trigger('click') + }) + + it('shows an cancel icon', () => { + expect(wrapper.find('svg.bi-x-circle').exists()).toBeTruthy() + }) + + it('closes the input when cancel icon is clicked', async () => { + await wrapper.find('svg.bi-x-circle').trigger('click') + expect(wrapper.find('input').exists()).toBeFalsy() + }) + + it('does not change the userdate when cancel is clicked', async () => { + await wrapper.findAll('input').at(0).setValue('Petra') + await wrapper.findAll('input').at(1).setValue('Lustiger') + await wrapper.find('textarea').setValue('Keine Nickelbrille') + await wrapper.find('svg.bi-x-circle').trigger('click') + expect(wrapper.findAll('div.col').at(2).text()).toBe('Peter') + expect(wrapper.findAll('div.col').at(4).text()).toBe('Lustig') + expect(wrapper.findAll('div.col').at(6).text()).toBe('') + }) + + it('has a submit button', () => { + expect(wrapper.find('button[type="submit"]').exists()).toBeTruthy() + }) + + it('does not enable submit button when data is not changed', async () => { + await wrapper.find('form').trigger('keyup') + expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled') + }) + + describe('successfull submit', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.findAll('input').at(0).setValue('Petra') + await wrapper.findAll('input').at(1).setValue('Lustiger') + await wrapper.find('textarea').setValue('Keine Nickelbrille') + await wrapper.find('form').trigger('keyup') + await wrapper.find('button[type="submit"]').trigger('click') + await flushPromises() + }) + + it('calls the loginAPI', () => { + expect(mockAPIcall).toBeCalledWith(1, 'user@example.org', { + firstName: 'Petra', + lastName: 'Lustiger', + description: 'Keine Nickelbrille', + }) + }) + + it('commits firstname to store', () => { + expect(storeCommitMock).toBeCalledWith('firstName', 'Petra') + }) + + it('commits lastname to store', () => { + expect(storeCommitMock).toBeCalledWith('lastName', 'Lustiger') + }) + + it('commits description to store', () => { + expect(storeCommitMock).toBeCalledWith('description', 'Keine Nickelbrille') + }) + + it('toasts a success message', () => { + expect(toastSuccessMock).toBeCalledWith('site.profil.user-data.change-success') + }) + + it('has an edit button again', () => { + expect(wrapper.find('svg.bi-pencil').exists()).toBeTruthy() + }) + }) + + describe('submit results in server error', () => { + beforeEach(async () => { + jest.clearAllMocks() + mockAPIcall.mockReturnValue({ success: false, result: { message: 'Error' } }) + await wrapper.findAll('input').at(0).setValue('Petra') + await wrapper.findAll('input').at(1).setValue('Lustiger') + await wrapper.find('textarea').setValue('Keine Nickelbrille') + await wrapper.find('form').trigger('keyup') + await wrapper.find('button[type="submit"]').trigger('click') + await flushPromises() + }) + + it('calls the loginAPI', () => { + expect(mockAPIcall).toBeCalledWith(1, 'user@example.org', { + firstName: 'Petra', + lastName: 'Lustiger', + description: 'Keine Nickelbrille', + }) + }) + + it('toasts an error message', () => { + expect(toastErrorMock).toBeCalledWith('Error') + }) + }) + }) + }) +}) From 518bb679eba05615b8eb238cf16eef3ffda09581 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 11:45:56 +0200 Subject: [PATCH 33/71] coverage frontend to 37% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 822dfeb24..4aec1dfd3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -206,7 +206,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 35 + min_coverage: 37 token: ${{ github.token }} ############################################################################## From b45b7cf03b3273fdd580d922cbd506f0f023dcd4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 14:28:34 +0200 Subject: [PATCH 34/71] load all validation rules for unit tests --- frontend/src/main.js | 3 + frontend/src/validation-rules.js | 169 ++++++++++++++++--------------- frontend/test/testSetup.js | 14 ++- 3 files changed, 100 insertions(+), 86 deletions(-) diff --git a/frontend/src/main.js b/frontend/src/main.js index 0e6fd0ef2..dff366780 100755 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -3,6 +3,7 @@ import DashboardPlugin from './plugins/dashboard-plugin' import App from './App.vue' import i18n from './i18n.js' import './validation-rules' +import { loadAllRules } from './validation-rules' import { store } from './store/store' @@ -12,6 +13,8 @@ import router from './routes/router' Vue.use(DashboardPlugin) Vue.config.productionTip = false +loadAllRules(i18n) + router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !store.state.sessionId) { next({ path: '/login' }) diff --git a/frontend/src/validation-rules.js b/frontend/src/validation-rules.js index e92e820bb..4476e3de2 100644 --- a/frontend/src/validation-rules.js +++ b/frontend/src/validation-rules.js @@ -1,104 +1,105 @@ -import i18n from './i18n.js' import { configure, extend } from 'vee-validate' // eslint-disable-next-line camelcase import { required, email, min, max, is_not } from 'vee-validate/dist/rules' import loginAPI from './apis/loginAPI' -configure({ - defaultMessage: (field, values) => { - values._field_ = i18n.t(`fields.${field}`) - return i18n.t(`validations.messages.${values._rule_}`, values) - }, -}) +export const loadAllRules = (i18nCallback) => { + configure({ + defaultMessage: (field, values) => { + values._field_ = i18nCallback.t(`fields.${field}`) + return i18nCallback.t(`validations.messages.${values._rule_}`, values) + }, + }) -extend('email', { - ...email, - message: (_, values) => i18n.t('validations.messages.email', values), -}) + extend('email', { + ...email, + message: (_, values) => i18nCallback.t('validations.messages.email', values), + }) -extend('required', { - ...required, - message: (_, values) => i18n.t('validations.messages.required', values), -}) + extend('required', { + ...required, + message: (_, values) => i18nCallback.t('validations.messages.required', values), + }) -extend('min', { - ...min, - message: (_, values) => i18n.t('validations.messages.min', values), -}) + extend('min', { + ...min, + message: (_, values) => i18nCallback.t('validations.messages.min', values), + }) -extend('max', { - ...max, - message: (_, values) => i18n.t('validations.messages.max', values), -}) + extend('max', { + ...max, + message: (_, values) => i18nCallback.t('validations.messages.max', values), + }) -extend('gddSendAmount', { - validate(value, { min, max }) { - value = value.replace(',', '.') - return value.match(/^[0-9]+(\.[0-9]{0,2})?$/) && Number(value) >= min && Number(value) <= max - }, - params: ['min', 'max'], - message: (_, values) => { - values.min = i18n.n(values.min, 'ungroupedDecimal') - values.max = i18n.n(values.max, 'ungroupedDecimal') - return i18n.t('form.validation.gddSendAmount', values) - }, -}) + extend('gddSendAmount', { + validate(value, { min, max }) { + value = value.replace(',', '.') + return value.match(/^[0-9]+(\.[0-9]{0,2})?$/) && Number(value) >= min && Number(value) <= max + }, + params: ['min', 'max'], + message: (_, values) => { + values.min = i18nCallback.n(values.min, 'ungroupedDecimal') + values.max = i18nCallback.n(values.max, 'ungroupedDecimal') + return i18nCallback.t('form.validation.gddSendAmount', values) + }, + }) -extend('gddUsernameUnique', { - async validate(value) { - const result = await loginAPI.checkUsername(value) - return result.result.data.state === 'success' - }, - message: (_, values) => i18n.t('form.validation.usernmae-unique', values), -}) + extend('gddUsernameUnique', { + async validate(value) { + const result = await loginAPI.checkUsername(value) + return result.result.data.state === 'success' + }, + message: (_, values) => i18nCallback.t('form.validation.usernmae-unique', values), + }) -extend('gddUsernameRgex', { - validate(value) { - return !!value.match(/^[a-zA-Z][-_a-zA-Z0-9]{2,}$/) - }, - message: (_, values) => i18n.t('form.validation.usernmae-regex', values), -}) + extend('gddUsernameRgex', { + validate(value) { + return !!value.match(/^[a-zA-Z][-_a-zA-Z0-9]{2,}$/) + }, + message: (_, values) => i18nCallback.t('form.validation.usernmae-regex', values), + }) -// eslint-disable-next-line camelcase -extend('is_not', { // eslint-disable-next-line camelcase - ...is_not, - message: (_, values) => i18n.t('form.validation.is-not', values), -}) + extend('is_not', { + // eslint-disable-next-line camelcase + ...is_not, + message: (_, values) => i18nCallback.t('form.validation.is-not', values), + }) -// Password validation + // Password validation -extend('containsLowercaseCharacter', { - validate(value) { - return !!value.match(/[a-z]+/) - }, - message: (_, values) => i18n.t('site.signup.lowercase', values), -}) + extend('containsLowercaseCharacter', { + validate(value) { + return !!value.match(/[a-z]+/) + }, + message: (_, values) => i18nCallback.t('site.signup.lowercase', values), + }) -extend('containsUppercaseCharacter', { - validate(value) { - return !!value.match(/[A-Z]+/) - }, - message: (_, values) => i18n.t('site.signup.uppercase', values), -}) + extend('containsUppercaseCharacter', { + validate(value) { + return !!value.match(/[A-Z]+/) + }, + message: (_, values) => i18nCallback.t('site.signup.uppercase', values), + }) -extend('containsNumericCharacter', { - validate(value) { - return !!value.match(/[0-9]+/) - }, - message: (_, values) => i18n.t('site.signup.one_number', values), -}) + extend('containsNumericCharacter', { + validate(value) { + return !!value.match(/[0-9]+/) + }, + message: (_, values) => i18nCallback.t('site.signup.one_number', values), + }) -extend('atLeastEightCharactera', { - validate(value) { - return !!value.match(/.{8,}/) - }, - message: (_, values) => i18n.t('site.signup.minimum', values), -}) + extend('atLeastEightCharactera', { + validate(value) { + return !!value.match(/.{8,}/) + }, + message: (_, values) => i18nCallback.t('site.signup.minimum', values), + }) -extend('samePassword', { - validate(value, [pwd]) { - return value === pwd - }, - message: (_, values) => i18n.t('site.signup.dont_match', values), -}) + extend('samePassword', { + validate(value, [pwd]) { + return value === pwd + }, + message: (_, values) => i18nCallback.t('site.signup.dont_match', values), + }) +} diff --git a/frontend/test/testSetup.js b/frontend/test/testSetup.js index 26d311941..565ebc33f 100644 --- a/frontend/test/testSetup.js +++ b/frontend/test/testSetup.js @@ -1,10 +1,11 @@ import { createLocalVue } from '@vue/test-utils' import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' import Vuex from 'vuex' + import { ValidationProvider, ValidationObserver, extend } from 'vee-validate' import * as rules from 'vee-validate/dist/rules' - import { messages } from 'vee-validate/dist/locale/en.json' + import RegeneratorRuntime from 'regenerator-runtime' import SideBar from '@/components/SidebarPlugin' import VueQrcode from 'vue-qrcode' @@ -14,7 +15,7 @@ import VueMoment from 'vue-moment' import clickOutside from '@/directives/click-ouside.js' import { focus } from 'vue-focus' -global.localVue = createLocalVue() +import { loadAllRules } from '../src/validation-rules' Object.keys(rules).forEach((rule) => { extend(rule, { @@ -23,6 +24,15 @@ Object.keys(rules).forEach((rule) => { }) }) +const i18nMock = { + t: (identifier, values) => identifier, + n: (value, format) => value, +} + +loadAllRules(i18nMock) + +global.localVue = createLocalVue() + global.localVue.use(BootstrapVue) global.localVue.use(Vuex) global.localVue.use(IconsPlugin) From 2d3d2579b59440e9b4d3a6a26c04638ea38b7f86 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 14:35:52 +0200 Subject: [PATCH 35/71] tests are working again --- frontend/src/main.js | 1 - frontend/src/views/Pages/ForgotPassword.spec.js | 4 +--- frontend/src/views/Pages/Login.spec.js | 4 ++-- frontend/src/views/Pages/Register.spec.js | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/frontend/src/main.js b/frontend/src/main.js index dff366780..9e1b4c06b 100755 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -2,7 +2,6 @@ import Vue from 'vue' import DashboardPlugin from './plugins/dashboard-plugin' import App from './App.vue' import i18n from './i18n.js' -import './validation-rules' import { loadAllRules } from './validation-rules' import { store } from './store/store' diff --git a/frontend/src/views/Pages/ForgotPassword.spec.js b/frontend/src/views/Pages/ForgotPassword.spec.js index 4e6c3b834..df60568b9 100644 --- a/frontend/src/views/Pages/ForgotPassword.spec.js +++ b/frontend/src/views/Pages/ForgotPassword.spec.js @@ -83,9 +83,7 @@ describe('ForgotPassword', () => { }) it('displays an error', () => { - expect(form.find('div.invalid-feedback').text()).toEqual( - 'The Email field must be a valid email', - ) + expect(form.find('div.invalid-feedback').text()).toEqual('validations.messages.email') }) it('does not call the API', () => { diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index 2339cd341..4be82684a 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -123,7 +123,7 @@ describe('Login', () => { await wrapper.find('form').trigger('submit') await flushPromises() expect(wrapper.findAll('div.invalid-feedback').at(0).text()).toBe( - 'The Email field is required', + 'validations.messages.required', ) }) @@ -131,7 +131,7 @@ describe('Login', () => { await wrapper.find('form').trigger('submit') await flushPromises() expect(wrapper.findAll('div.invalid-feedback').at(1).text()).toBe( - 'The form.password field is required', + 'validations.messages.required', ) }) }) diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index 36ee6987b..85f3ca38f 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -84,7 +84,7 @@ describe('Register', () => { wrapper.find('#registerEmail').setValue('no_valid@Email') await flushPromises() await expect(wrapper.find('#registerEmailLiveFeedback').text()).toEqual( - 'The Email field must be a valid email', + 'validations.messages.email', ) }) From ce68dc8528a9a1f0bd1860c9940d7abf846cf816 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 15:18:00 +0200 Subject: [PATCH 36/71] remove all validation rule extends that are not needed --- .../Inputs/InputPasswordConfirmation.spec.js | 17 --------------- frontend/src/plugins/dashboard-plugin.js | 17 --------------- frontend/src/validation-rules.js | 5 +++++ .../src/views/Pages/ResetPassword.spec.js | 17 --------------- .../UserCard_FormUserPasswort.spec.js | 17 --------------- .../UserProfile/UserCard_FormUsername.spec.js | 21 +++++++------------ 6 files changed, 13 insertions(+), 81 deletions(-) diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js b/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js index ef3b5d64e..633dea44a 100644 --- a/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js @@ -1,24 +1,7 @@ import { mount } from '@vue/test-utils' -import { extend } from 'vee-validate' import InputPasswordConfirmation from './InputPasswordConfirmation' -const rules = [ - 'containsLowercaseCharacter', - 'containsUppercaseCharacter', - 'containsNumericCharacter', - 'atLeastEightCharactera', - 'samePassword', -] - -rules.forEach((rule) => { - extend(rule, { - validate(value) { - return true - }, - }) -}) - const localVue = global.localVue describe('InputPasswordConfirmation', () => { diff --git a/frontend/src/plugins/dashboard-plugin.js b/frontend/src/plugins/dashboard-plugin.js index 2edac0995..8ef34e4ab 100755 --- a/frontend/src/plugins/dashboard-plugin.js +++ b/frontend/src/plugins/dashboard-plugin.js @@ -1,5 +1,4 @@ import '@/polyfills' -import { configure, extend } from 'vee-validate' import GlobalComponents from './globalComponents' import GlobalDirectives from './globalDirectives' import SideBar from '@/components/SidebarPlugin' @@ -14,8 +13,6 @@ import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' // asset imports import '@/assets/scss/argon.scss' import '@/assets/vendor/nucleo/css/nucleo.css' -import * as rules from 'vee-validate/dist/rules' -import { messages } from 'vee-validate/dist/locale/en.json' import VueQrcodeReader from 'vue-qrcode-reader' import VueQrcode from 'vue-qrcode' @@ -28,13 +25,6 @@ import VueMoment from 'vue-moment' import Loading from 'vue-loading-overlay' import 'vue-loading-overlay/dist/vue-loading.css' -Object.keys(rules).forEach((rule) => { - extend(rule, { - ...rules[rule], // copies rule configuration - message: messages[rule], // assign message - }) -}) - export default { install(Vue) { Vue.use(GlobalComponents) @@ -49,12 +39,5 @@ export default { Vue.use(VueQrcode) Vue.use(FlatPickr) Vue.use(Loading) - configure({ - classes: { - valid: 'is-valid', - invalid: 'is-invalid', - dirty: ['is-dirty', 'is-dirty'], // multiple classes per flag! - }, - }) }, } diff --git a/frontend/src/validation-rules.js b/frontend/src/validation-rules.js index 4476e3de2..59900b272 100644 --- a/frontend/src/validation-rules.js +++ b/frontend/src/validation-rules.js @@ -9,6 +9,11 @@ export const loadAllRules = (i18nCallback) => { values._field_ = i18nCallback.t(`fields.${field}`) return i18nCallback.t(`validations.messages.${values._rule_}`, values) }, + classes: { + valid: 'is-valid', + invalid: 'is-invalid', + dirty: ['is-dirty', 'is-dirty'], // multiple classes per flag! + }, }) extend('email', { diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 11bdad1ba..76a010b2a 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -2,23 +2,6 @@ import { mount, RouterLinkStub } from '@vue/test-utils' import loginAPI from '../../apis/loginAPI' import ResetPassword from './ResetPassword' import flushPromises from 'flush-promises' -import { extend } from 'vee-validate' - -const rules = [ - 'containsLowercaseCharacter', - 'containsUppercaseCharacter', - 'containsNumericCharacter', - 'atLeastEightCharactera', - 'samePassword', -] - -rules.forEach((rule) => { - extend(rule, { - validate(value) { - return true - }, - }) -}) jest.mock('../../apis/loginAPI') diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index fb435cedb..2d5d2a560 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -2,23 +2,6 @@ import { mount } from '@vue/test-utils' import UserCardFormPasswort from './UserCard_FormUserPasswort' import loginAPI from '../../../apis/loginAPI' import flushPromises from 'flush-promises' -import { extend } from 'vee-validate' - -const rules = [ - 'containsLowercaseCharacter', - 'containsUppercaseCharacter', - 'containsNumericCharacter', - 'atLeastEightCharactera', - 'samePassword', -] - -rules.forEach((rule) => { - extend(rule, { - validate(value) { - return true - }, - }) -}) jest.mock('../../../apis/loginAPI') diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js index 48bbe6b70..8b1c53751 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js @@ -1,29 +1,24 @@ import { mount } from '@vue/test-utils' -import { extend } from 'vee-validate' import UserCardFormUsername from './UserCard_FormUsername' import loginAPI from '../../../apis/loginAPI' import flushPromises from 'flush-promises' +import { extend } from 'vee-validate' jest.mock('../../../apis/loginAPI') -extend('gddUsernameRgex', { - validate(value) { - return true - }, -}) - -extend('gddUsernameUnique', { - validate(value) { - return true - }, -}) - const localVue = global.localVue const mockAPIcall = jest.fn((args) => { return { success: true } }) +// override this rule to avoid API call +extend('gddUsernameUnique', { + validate(value) { + return true + }, +}) + const toastErrorMock = jest.fn() const toastSuccessMock = jest.fn() const storeCommitMock = jest.fn() From 3544a20948feda604a7cdf37154516f0b0ceb9bc Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 15:26:25 +0200 Subject: [PATCH 37/71] coverage frontend to 41% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4aec1dfd3..2eb86e532 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -206,7 +206,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 37 + min_coverage: 41 token: ${{ github.token }} ############################################################################## From b2e09bf9ce782de8135604ddc619c80c45c7f124 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 15:52:39 +0200 Subject: [PATCH 38/71] test validation rules for new passworda --- .../Inputs/InputPasswordConfirmation.spec.js | 2 + .../src/views/Pages/ResetPassword.spec.js | 2 + .../UserCard_FormUserPasswort.spec.js | 51 +++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js b/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js index 633dea44a..953d0b960 100644 --- a/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.spec.js @@ -4,6 +4,8 @@ import InputPasswordConfirmation from './InputPasswordConfirmation' const localVue = global.localVue +// validation is tested in src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js + describe('InputPasswordConfirmation', () => { let wrapper diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 76a010b2a..a0a86a24d 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -3,6 +3,8 @@ import loginAPI from '../../apis/loginAPI' import ResetPassword from './ResetPassword' import flushPromises from 'flush-promises' +// validation is tested in src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js + jest.mock('../../apis/loginAPI') const localVue = global.localVue diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index 2d5d2a560..f00a4d2b4 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -105,6 +105,57 @@ describe('UserCardFormUserPasswort', () => { expect(form.find('button[type="submit"]').exists()).toBeTruthy() }) + describe('validation', () => { + it('displays all password requirements', () => { + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(5) + expect(feedbackArray.at(0).text()).toBe('validations.messages.required') + expect(feedbackArray.at(1).text()).toBe('site.signup.lowercase') + expect(feedbackArray.at(2).text()).toBe('site.signup.uppercase') + expect(feedbackArray.at(3).text()).toBe('site.signup.one_number') + expect(feedbackArray.at(4).text()).toBe('site.signup.minimum') + }) + + it('removes first message when a character is given', async () => { + await wrapper.findAll('input').at(1).setValue('@') + await flushPromises() + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(4) + expect(feedbackArray.at(0).text()).toBe('site.signup.lowercase') + }) + + it('removes first and second message when a lowercase character is given', async () => { + await wrapper.findAll('input').at(1).setValue('a') + await flushPromises() + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(3) + expect(feedbackArray.at(0).text()).toBe('site.signup.uppercase') + }) + + it('removes the first three messages when a lowercase and uppercase characters are given', async () => { + await wrapper.findAll('input').at(1).setValue('Aa') + await flushPromises() + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(2) + expect(feedbackArray.at(0).text()).toBe('site.signup.one_number') + }) + + it('removes the first four messages when a lowercase, uppercase and numeric characters are given', async () => { + await wrapper.findAll('input').at(1).setValue('Aa1') + await flushPromises() + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(1) + expect(feedbackArray.at(0).text()).toBe('site.signup.minimum') + }) + + it('removes all messages when all rules are fulfilled', async () => { + await wrapper.findAll('input').at(1).setValue('Aa123456') + await flushPromises() + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(0) + }) + }) + describe('submit', () => { describe('valid data', () => { beforeEach(async () => { From 1cb01182ae1c1168c7c3f83b73d059278133f5d5 Mon Sep 17 00:00:00 2001 From: Dario Rekowski on RockPI Date: Tue, 6 Jul 2021 13:58:56 +0000 Subject: [PATCH 39/71] add api/getDecayStartBlock function --- .../src/Controller/AppRequestsController.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/community_server/src/Controller/AppRequestsController.php b/community_server/src/Controller/AppRequestsController.php index 15c68cece..018e0af49 100644 --- a/community_server/src/Controller/AppRequestsController.php +++ b/community_server/src/Controller/AppRequestsController.php @@ -393,6 +393,16 @@ class AppRequestsController extends AppController $this->set('body', $body); } + public function getDecayStartBlock() + { + $transactionsTable = TableRegistry::getTableLocator()->get('Transactions'); + $decayStartBlock = $transactionsTable->find()->where(['transaction_type_id' => 9]); + if(!$decayStartBlock->count()) { + return $this->returnJson(['state' => 'error', 'msg' => 'not found']); + } + return $this->returnJson(['state' => 'success', 'decay_start' => $decayStartBlock->first()->received]); + } + private function acquireAccessToken($session_id) { From c2ca3927bcb0a3950c28185dbfc91c7559a154b3 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 6 Jul 2021 16:02:04 +0200 Subject: [PATCH 40/71] style decay fix --- frontend/src/components/DecayInformation.vue | 66 +++++------ .../AccountOverview/GddTransactionList.vue | 108 ++++++++++++++---- 2 files changed, 117 insertions(+), 57 deletions(-) diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue index 4bd5d31be..4035bad3c 100644 --- a/frontend/src/components/DecayInformation.vue +++ b/frontend/src/components/DecayInformation.vue @@ -1,40 +1,34 @@ @@ -48,7 +42,7 @@ export default { decay_start: 0, decay_end: 0, }, - form: '', + decaytyp: '', }, data() { return { diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue index be0ccf87d..3c93e449b 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue @@ -4,54 +4,120 @@
+
{{ getProperties(item).operator }} - {{ $n(item.balance, 'decimal') }} + {{ $n(item.balance, 'decimal') }} + + {{ $n(item.balance, 'decimal') }} + +
+
+ +
+
- {{ item.name ? item.name : $t('decay') }} + {{ item.name ? item.name : '' }} + + Vergänglichkeit seit der letzten Transaktion +
{{ $d($moment(item.date), 'long') }}
- - +
+
i
- + + -
+
+ + {{ item.type === 'receive' ? 'empfangen:' : 'gesendet:' }}
+
+ + + {{ item.type === 'creation' ? 'geschöpft:' : '' }} +

{{ $n(item.balance, 'decimal') }} GDD

-
+
am:
- {{ $d($moment(item.date), 'long') }} -
-
-
{{ item.type === 'receive' ? 'von:' : 'an:' }}
- {{ item.name }} -
-
- {{ - item.type === 'receive' ? 'Nachricht vom Absender:' : 'Nachricht an Empfänger:' - }} -
-
{{ item.memo }}
- + + + + {{ $d($moment(item.date), 'long') }} + +
{{ item.type === 'receive' ? 'von:' : 'an:' }}
+ + + {{ item.name }} + 5 + +
+
+ {{ + item.type === 'receive' ? 'Nachricht vom Absender:' : 'Nachricht an Empfänger:' + }} +
+ + + + {{ item.memo }} + + +
+
+
Dein Eintrag aus der Community wurde bestätigt.
+ +
+ + + 5 Stunden hilfe bei Gartenarbeit. Meine 80 jährige Nachbarin kann zur Zeit + nicht in Ihrem Garten arbeiten. + + + ansehen + +
+ +
+ Deinem Konto wurden am + {{ $d($moment(item.date), 'long') }} +
{{ $n(item.balance, 'decimal') }} GDD geschöpft
+
+ +
From 89621d78e787de272438c6f6a6b01aad54b36847 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 16:33:01 +0200 Subject: [PATCH 41/71] test for transaction form --- .../GddSend/TransactionForm.spec.js | 90 +++++++++++++++++-- .../GddSend/TransactionForm.vue | 11 +-- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.spec.js b/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.spec.js index 199cba4f3..28b769a3c 100644 --- a/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.spec.js +++ b/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.spec.js @@ -1,5 +1,6 @@ import { mount } from '@vue/test-utils' import TransactionForm from './TransactionForm' +import flushPromises from 'flush-promises' const localVue = global.localVue @@ -19,8 +20,12 @@ describe('GddSend', () => { }, } + const propsData = { + balance: 100.0, + } + const Wrapper = () => { - return mount(TransactionForm, { localVue, mocks }) + return mount(TransactionForm, { localVue, mocks, propsData }) } describe('mount', () => { @@ -53,6 +58,18 @@ describe('GddSend', () => { 'E-Mail', ) }) + + it('flushes an error message when no valid email is given', async () => { + await wrapper.find('#input-group-1').find('input').setValue('a') + await flushPromises() + expect(wrapper.find('span.errors').text()).toBe('validations.messages.email') + }) + + it('trims the email after blur', async () => { + await wrapper.find('#input-group-1').find('input').setValue(' valid@email.com ') + await flushPromises() + expect(wrapper.vm.form.email).toBe('valid@email.com') + }) }) describe('ammount field', () => { @@ -73,6 +90,24 @@ describe('GddSend', () => { '0.01', ) }) + + it('flushes an error message when no valid amount is given', async () => { + await wrapper.find('#input-group-2').find('input').setValue('a') + await flushPromises() + expect(wrapper.find('span.errors').text()).toBe('form.validation.gddSendAmount') + }) + + it('flushes an error message when amount is too high', async () => { + await wrapper.find('#input-group-2').find('input').setValue('123.34') + await flushPromises() + expect(wrapper.find('span.errors').text()).toBe('form.validation.gddSendAmount') + }) + + it('flushes no errors when amount is valid', async () => { + await wrapper.find('#input-group-2').find('input').setValue('87.34') + await flushPromises() + expect(wrapper.find('span.errors').exists()).toBeFalsy() + }) }) describe('message text box', () => { @@ -89,6 +124,18 @@ describe('GddSend', () => { it('has a label form.memo', () => { expect(wrapper.find('label.input-3').text()).toBe('form.memo') }) + + it('flushes an error message when memo is less than 5 characters', async () => { + await wrapper.find('#input-group-3').find('textarea').setValue('a') + await flushPromises() + expect(wrapper.find('span.errors').text()).toBe('validations.messages.min') + }) + + it('flushes no error message when memo is valid', async () => { + await wrapper.find('#input-group-3').find('textarea').setValue('Long enough') + await flushPromises() + expect(wrapper.find('span.errors').exists()).toBeFalsy() + }) }) describe('cancel button', () => { @@ -100,11 +147,42 @@ describe('GddSend', () => { expect(wrapper.find('button[type="reset"]').text()).toBe('form.reset') }) - it.skip('clears the email field on click', async () => { - wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv') - wrapper.find('button[type="reset"]').trigger('click') - await wrapper.vm.$nextTick() - expect(wrapper.vm.form.email).toBeNull() + it('clears all fields on click', async () => { + await wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv') + await wrapper.find('#input-group-2').find('input').setValue('87.23') + await wrapper.find('#input-group-3').find('textarea').setValue('Long enugh') + await flushPromises() + expect(wrapper.vm.form.email).toBe('someone@watches.tv') + expect(wrapper.vm.form.amount).toBe('87.23') + expect(wrapper.vm.form.memo).toBe('Long enugh') + await wrapper.find('button[type="reset"]').trigger('click') + await flushPromises() + expect(wrapper.vm.form.email).toBe('') + expect(wrapper.vm.form.amount).toBe('') + expect(wrapper.vm.form.memo).toBe('') + }) + }) + + describe('submit', () => { + beforeEach(async () => { + await wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv') + await wrapper.find('#input-group-2').find('input').setValue('87.23') + await wrapper.find('#input-group-3').find('textarea').setValue('Long enugh') + await wrapper.find('form').trigger('submit') + await flushPromises() + }) + + it('emits set-transaction', async () => { + expect(wrapper.emitted('set-transaction')).toBeTruthy() + expect(wrapper.emitted('set-transaction')).toEqual([ + [ + { + email: 'someone@watches.tv', + amount: 87.23, + memo: 'Long enugh', + }, + ], + ]) }) }) }) diff --git a/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.vue b/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.vue index c9c9df7b3..74a4a8de1 100644 --- a/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.vue +++ b/frontend/src/views/Pages/AccountOverview/GddSend/TransactionForm.vue @@ -168,7 +168,7 @@ export default { }, methods: { onSubmit() { - this.normalizeAmount() + this.normalizeAmount(true) this.$emit('set-transaction', { email: this.form.email, amount: this.form.amountValue, @@ -181,10 +181,11 @@ export default { this.form.amount = '' this.form.memo = '' }, - setTransaction(data) { - this.form.email = data.email - this.form.amount = data.amount - }, + /* + setTransaction(data) { + this.form.email = data.email + this.form.amount = data.amount + }, */ normalizeAmount(isValid) { this.amountFocused = false if (!isValid) return From ad9cdabfa930b7c9da92deea975075bc15449a80 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 16:40:58 +0200 Subject: [PATCH 42/71] coverage frontend to 44% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2eb86e532..a7f7b73c9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -206,7 +206,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 41 + min_coverage: 44 token: ${{ github.token }} ############################################################################## From 2d20cbee17658b21c980097fb6e78e221c1a0614 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 6 Jul 2021 18:24:37 +0200 Subject: [PATCH 43/71] feat: Test AccountOverview --- .../src/views/Pages/AccountOverview.spec.js | 105 +++++++++++++++++- frontend/src/views/Pages/AccountOverview.vue | 4 +- .../views/Pages/AccountOverview/GddStatus.vue | 2 +- 3 files changed, 102 insertions(+), 9 deletions(-) diff --git a/frontend/src/views/Pages/AccountOverview.spec.js b/frontend/src/views/Pages/AccountOverview.spec.js index 031828129..17f3aedba 100644 --- a/frontend/src/views/Pages/AccountOverview.spec.js +++ b/frontend/src/views/Pages/AccountOverview.spec.js @@ -1,34 +1,127 @@ -import { shallowMount } from '@vue/test-utils' +import { mount } from '@vue/test-utils' import AccountOverview from './AccountOverview' +import communityAPI from '../../apis/communityAPI.js' + +jest.mock('../../apis/communityAPI.js') + +const sendMock = jest.fn() +sendMock.mockReturnValue({ success: true }) + +communityAPI.send = sendMock const localVue = global.localVue describe('AccountOverview', () => { let wrapper + const propsData = { + balance: 123.45, + transactionCount: 1, + } + const mocks = { $t: jest.fn((t) => t), + $store: { + state: { + sessionId: 1, + }, + }, + $n: jest.fn((n) => String(n)), } const Wrapper = () => { - return shallowMount(AccountOverview, { localVue, mocks }) + return mount(AccountOverview, { localVue, mocks, propsData }) } - describe('shallow Mount', () => { + describe('mount', () => { beforeEach(() => { wrapper = Wrapper() }) it('has a status line', () => { - expect(wrapper.find('gdd-status-stub').exists()).toBeTruthy() + expect(wrapper.find('div.gdd-status').exists()).toBeTruthy() }) it('has a send field', () => { - expect(wrapper.find('gdd-send-stub').exists()).toBeTruthy() + expect(wrapper.find('div.gdd-send').exists()).toBeTruthy() }) it('has a transactions table', () => { - expect(wrapper.find('gdd-transaction-list-stub').exists()).toBeTruthy() + expect(wrapper.find('div.gdd-transaction-list').exists()).toBeTruthy() + }) + + describe('transaction form', () => { + it('steps forward in the dialog', () => { + wrapper.findComponent({ name: 'TransactionForm' }).vm.$emit('set-transaction', { + email: 'user@example.org', + amount: 23.45, + memo: 'Make the best of it!', + }) + expect(wrapper.vm.currentTransactionStep).toBe(1) + }) + }) + + describe('confirm transaction', () => { + beforeEach(() => { + wrapper.setData({ + currentTransactionStep: 1, + transactionData: { + email: 'user@example.org', + amount: 23.45, + memo: 'Make the best of it!', + }, + }) + }) + + it('resets the transaction process when on-reset is emitted', async () => { + await wrapper.findComponent({ name: 'TransactionConfirmation' }).vm.$emit('on-reset') + expect(wrapper.vm.currentTransactionStep).toBe(0) + expect(wrapper.vm.transactionData).toEqual({ + email: '', + amount: 0, + memo: '', + }) + }) + + describe('transaction is confirmed and server response is success', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper + .findComponent({ name: 'TransactionConfirmation' }) + .vm.$emit('send-transaction') + }) + + it('calls the API when send-transaction is emitted', async () => { + expect(sendMock).toBeCalledWith(1, { + email: 'user@example.org', + amount: 23.45, + memo: 'Make the best of it!', + }) + }) + + it('emits update-balance', () => { + expect(wrapper.emitted('update-balance')).toBeTruthy() + expect(wrapper.emitted('update-balance')).toEqual([[23.45]]) + }) + + it('shows the succes page', () => { + expect(wrapper.find('div.card-body').text()).toContain('form.send_transaction_success') + }) + }) + + describe('transaction is confirmed and server response is error', () => { + beforeEach(async () => { + jest.clearAllMocks() + sendMock.mockReturnValue({ success: false }) + await wrapper + .findComponent({ name: 'TransactionConfirmation' }) + .vm.$emit('send-transaction') + }) + + it('shows the error page', () => { + expect(wrapper.find('div.card-body').text()).toContain('form.send_transaction_error') + }) + }) }) }) }) diff --git a/frontend/src/views/Pages/AccountOverview.vue b/frontend/src/views/Pages/AccountOverview.vue index 35490e093..cde611778 100644 --- a/frontend/src/views/Pages/AccountOverview.vue +++ b/frontend/src/views/Pages/AccountOverview.vue @@ -69,7 +69,7 @@ export default { data() { return { timestamp: Date.now(), - transactionData: EMPTY_TRANSACTION_DATA, + transactionData: { ...EMPTY_TRANSACTION_DATA }, error: false, currentTransactionStep: 0, loading: false, @@ -110,7 +110,7 @@ export default { this.loading = false }, onReset() { - this.transactionData = EMPTY_TRANSACTION_DATA + this.transactionData = { ...EMPTY_TRANSACTION_DATA } this.currentTransactionStep = 0 }, updateTransactions(pagination) { diff --git a/frontend/src/views/Pages/AccountOverview/GddStatus.vue b/frontend/src/views/Pages/AccountOverview/GddStatus.vue index c0c4869dd..4ab675485 100644 --- a/frontend/src/views/Pages/AccountOverview/GddStatus.vue +++ b/frontend/src/views/Pages/AccountOverview/GddStatus.vue @@ -1,5 +1,5 @@ diff --git a/frontend/src/plugins/dashboard-plugin.js b/frontend/src/plugins/dashboard-plugin.js index 8ef34e4ab..c71b3742b 100755 --- a/frontend/src/plugins/dashboard-plugin.js +++ b/frontend/src/plugins/dashboard-plugin.js @@ -5,7 +5,7 @@ import SideBar from '@/components/SidebarPlugin' import PortalVue from 'portal-vue' -import VueBootstrapToasts from 'vue-bootstrap-toasts' +import Toasted from 'vue-toasted' // vue-bootstrap import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' @@ -33,11 +33,15 @@ export default { Vue.use(PortalVue) Vue.use(BootstrapVue) Vue.use(IconsPlugin) - Vue.use(VueBootstrapToasts) Vue.use(VueMoment) Vue.use(VueQrcodeReader) Vue.use(VueQrcode) Vue.use(FlatPickr) Vue.use(Loading) + Vue.use(Toasted, { + position: 'top-center', + duration: 2500, + fullWidth: true, + }) }, } diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index 4be82684a..8fe428020 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -49,7 +49,7 @@ describe('Login', () => { $router: { push: mockRouterPush, }, - $toast: { + $toasted: { error: toastErrorMock, }, } diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index f7382ef89..6d4b6d6e9 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -91,7 +91,7 @@ export default { loader.hide() } else { loader.hide() - this.$toast.error(this.$t('error.no-account')) + this.$toasted.error(this.$t('error.no-account')) } }, }, diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index a0a86a24d..e7689e3e7 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -53,7 +53,7 @@ describe('ResetPassword', () => { optin: '123', }, }, - $toast: { + $toasted: { error: toasterMock, }, $router: { diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index 616fa85c1..66a3dcfe5 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -80,7 +80,7 @@ export default { */ this.$router.push('/thx/reset') } else { - this.$toast.error(result.result.message) + this.$toasted.error(result.result.message) } }, async authenticate() { @@ -94,7 +94,7 @@ export default { this.sessionId = result.result.data.session_id this.email = result.result.data.user.email } else { - this.$toast.error(result.result.message) + this.$toasted.error(result.result.message) } loader.hide() this.pending = false diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js index 55d62bb05..5237a8d63 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js @@ -32,7 +32,7 @@ describe('UserCard_FormUsername', () => { }, commit: storeCommitMock, }, - $toast: { + $toasted: { success: toastSuccessMock, error: toastErrorMock, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue index 70162df14..3ad93470d 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue @@ -135,9 +135,9 @@ export default { this.$store.commit('lastName', this.form.lastName) this.$store.commit('description', this.form.description) this.showUserData = true - this.$toast.success(this.$t('site.profil.user-data.change-success')) + this.$toasted.success(this.$t('site.profil.user-data.change-success')) } else { - this.$toast.error(result.result.message) + this.$toasted.error(result.result.message) } }, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index f00a4d2b4..423fd5c30 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -26,7 +26,7 @@ describe('UserCardFormUserPasswort', () => { email: 'user@example.org', }, }, - $toast: { + $toasted: { success: toastSuccessMock, error: toastErrorMock, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue index 00cacfd21..7921f4037 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue @@ -83,10 +83,10 @@ export default { this.form.newPassword.password, ) if (result.success) { - this.$toast.success(this.$t('site.thx.reset')) + this.$toasted.success(this.$t('site.thx.reset')) this.cancelEdit() } else { - this.$toast.error(result.result.message) + this.$toasted.error(result.result.message) } }, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js index 8b1c53751..3227895ad 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js @@ -38,7 +38,7 @@ describe('UserCard_FormUsername', () => { }, commit: storeCommitMock, }, - $toast: { + $toasted: { success: toastSuccessMock, error: toastErrorMock, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue index e908fd08c..dc971acba 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue @@ -95,9 +95,9 @@ export default { this.$store.commit('username', this.form.username) this.username = this.form.username this.showUsername = true - this.$toast.success(this.$t('site.profil.user-data.change-success')) + this.$toasted.success(this.$t('site.profil.user-data.change-success')) } else { - this.$toast.error(result.result.message) + this.$toasted.error(result.result.message) this.showUsername = true this.username = this.$store.state.username this.form.username = this.$store.state.username diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 65f3ff71d..7f689a72c 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -13268,11 +13268,6 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -vue-bootstrap-toasts@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/vue-bootstrap-toasts/-/vue-bootstrap-toasts-1.0.7.tgz#111c38855941e8eb0538e21f41c173e2af67dd53" - integrity sha512-JhurJOAwdNcINQ/QlT701sx0r447YTGpvtxtmZNC9pwDvEqp2I0Pyv15jS4neWwYHkA1gXB42nBsDRcWcj1hlg== - vue-bootstrap-typeahead@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/vue-bootstrap-typeahead/-/vue-bootstrap-typeahead-0.2.6.tgz#8c1999a00bf4bf9fc906bae3a462482482cbc297" @@ -13475,6 +13470,11 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.9.0: resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== +vue-toasted@^1.1.28: + version "1.1.28" + resolved "https://registry.yarnpkg.com/vue-toasted/-/vue-toasted-1.1.28.tgz#dbabb83acc89f7a9e8765815e491d79f0dc65c26" + integrity sha512-UUzr5LX51UbbiROSGZ49GOgSzFxaMHK6L00JV8fir/CYNJCpIIvNZ5YmS4Qc8Y2+Z/4VVYRpeQL2UO0G800Raw== + vue2-transitions@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/vue2-transitions/-/vue2-transitions-0.2.3.tgz#69c9d75b1db05f231b80980c03459d68490ba27d" From f4076e681332402dc9c3135885aa9fd7cbfaeb2f Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 8 Jul 2021 12:05:18 +0200 Subject: [PATCH 57/71] add close button to toasts --- frontend/src/plugins/dashboard-plugin.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/plugins/dashboard-plugin.js b/frontend/src/plugins/dashboard-plugin.js index c71b3742b..b32bb20cd 100755 --- a/frontend/src/plugins/dashboard-plugin.js +++ b/frontend/src/plugins/dashboard-plugin.js @@ -40,8 +40,14 @@ export default { Vue.use(Loading) Vue.use(Toasted, { position: 'top-center', - duration: 2500, + duration: 5000, fullWidth: true, + action: { + text: 'x', + onClick: (e, toastObject) => { + toastObject.goAway(0) + }, + }, }) }, } From cc7778b55d1baaa7be2d9440480e0fb27bb9a930 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 8 Jul 2021 15:55:32 +0200 Subject: [PATCH 58/71] fix style decay startblick --- frontend/src/components/DecayInformation.vue | 116 +++++++++++++----- frontend/src/locales/de.json | 22 +++- frontend/src/locales/en.json | 20 ++- .../AccountOverview/GddTransactionList.vue | 64 +++++++--- 4 files changed, 174 insertions(+), 48 deletions(-) diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue index 84b9a1310..c18bfdb3c 100644 --- a/frontend/src/components/DecayInformation.vue +++ b/frontend/src/components/DecayInformation.vue @@ -1,34 +1,90 @@ @@ -41,6 +97,7 @@ export default { decay_duration: '', decay_start: 0, decay_end: 0, + decay_start_block: 0, }, decaytyp: '', }, @@ -50,22 +107,21 @@ export default { b: 0, duration: {}, diff: {}, + decay_start_block_text_short: this.decay.decay_start_block + ? ' - Startblock Decay am: ' + this.$d(this.$moment.unix(this.decay.decay_start_block)) + : '', } }, - created() { - console.log("start", start) - }, methods: { - getDuration(start, end) { - console.log("start", start) - console.log("end", end) - this.a = new Date(start) - this.b = new Date(end) - this.a = this.$moment.unix(this.a) - this.b = this.$moment.unix(this.b) - this.diff = this.$moment.duration(this.a.diff(this.b)) - this.duration = this.diff._data - + getDuration(start, end) { + // console.log("start", start) + // console.log("end", end) + this.a = new Date(start) + this.b = new Date(end) + this.a = this.$moment.unix(this.a) + this.b = this.$moment.unix(this.b) + this.diff = this.$moment.duration(this.a.diff(this.b)) + this.duration = this.diff._data }, }, } diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 3c8098346..1781ea1cd 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -18,9 +18,25 @@ "de": "Deutsch", "en": "English" }, - "decay": "Vergänglichkeit", - "resieve": "", - + "decay": { + "decay": "Vergänglichkeit", + "decay_since_last_transaction":"Vergänglichkeit seit der letzten Transaktion", + "calculation_decay":"Berechnung der Vergänglichkeit", + "Starting_block_decay":"Startblock Vergänglichkeit", + "decay_introduced":"Die Vergänglichkeit wurde Eingeführt am", + "last_transaction":"Letzte Transaktion", + "past_time":"Vergangene Zeit", + "since_introduction":"seit Einführung der Vergänglichkeit", + "year":"Jahre", + "months":"Monate", + "days":"Tage", + "hours":"Stunden", + "minutes":"Minuten", + "seconds":"Sekunden", + "received":"empfangen", + "sent":"gesendet", + "created":"geschöpft" + }, "form": { "cancel": "Abbrechen", "reset": "Zurücksetzen", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 987605bd8..29a9b49c1 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -18,7 +18,25 @@ "de": "Deutsch", "en": "English" }, - "decay": "Decay", + "decay": { + "decay": "Decay", + "decay_since_last_transaction":"Decay since the last transaction", + "calculation_decay": "Calculation of Decay", + "Starting_block_decay": "Starting Block Decay", + "decay_introduced": "Decay was Introduced on", + "last_transaction": "Last transaction:", + "past_time": "Past time", + "since_introduction": "Since the introduction of Decay", + "year": "Years", + "months": "Months", + "days": "Days", + "hours": "Hours", + "minutes": "Minutes", + "seconds": "Seconds", + "received":"received", + "sent":"sent", + "created":"created" + }, "form": { "cancel":"Cancel", "reset": "Reset", diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue index 100385d9b..8524a87bb 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue @@ -6,11 +6,13 @@ v-bind:key="item.transaction_id" :style="item.type === 'decay' ? 'background-color:#f1e0ae3d' : ''" > +
+
- +
{{ getProperties(item).operator }} {{ $n(item.balance, 'decimal') }} @@ -22,43 +24,75 @@
- +
{{ item.name ? item.name : '' }} - Vergänglichkeit seit der letzten Transaktion + {{ $t('decay.decay_since_last_transaction') }}
{{ $d($moment(item.date), 'long') }}
- +
i
- + + + + +
+
+ {{ item.type === 'receive' ? 'von:' : 'an:' }} +
+
+ {{ item.name }} + +
+
+
+
+ {{ item.type === 'receive' ? 'Nachricht:' : 'Nachricht:' }} +
+
+ {{ item.memo }} +
+
+
+
+ + +
+
Schöpfung
+
Aus der Community
+
+
+
+ +
+
t.transaction_id === id) }, - updateTransactions() { this.$emit('update-transactions', { firstPage: this.currentPage, @@ -224,4 +260,4 @@ export default { padding-left: 0px; padding-right: 0px; } - \ No newline at end of file + From 9f3c1ea11e1ffd3a819af0d20cb8a1df710ce4b3 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 8 Jul 2021 15:58:52 +0200 Subject: [PATCH 59/71] fix style decay startblock delete old code --- .../AccountOverview/GddTransactionList.vue | 79 ------------------- 1 file changed, 79 deletions(-) diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue index 8524a87bb..002607041 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue @@ -76,85 +76,6 @@ -
From 956686b7aa4a1f9fa952284a82ed1a921ba2d243 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 8 Jul 2021 16:22:04 +0200 Subject: [PATCH 60/71] fix delete old code --- frontend/src/components/DecayInformation.vue | 35 -------------------- 1 file changed, 35 deletions(-) diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue index c18bfdb3c..760d3939d 100644 --- a/frontend/src/components/DecayInformation.vue +++ b/frontend/src/components/DecayInformation.vue @@ -53,39 +53,6 @@ - -
- - {{ $t('decay.calculation_decay') }} -
-
-
-
{{ $t('decay.Starting_block_decay') }} :
-
- {{ $t('decay.decay_introduced') }} : {{ $d($moment.unix(decay.decay_start), 'long') }} -
-
-
-
{{ $t('decay.last_transaction') }}:
- {{ $d($moment.unix(decay.decay_start), 'long') }} Uhr -
-
- {{ $t('decay.past_time') }} - {{ $t('decay.since_introduction') }} - : - {{ getDuration(decay.decay_end, decay.decay_start) }} - - {{ duration.years }} {{ $t('decay.year') }}, - {{ duration.months }} {{ $t('decay.months') }}, - {{ duration.days }} {{ $t('decay.days') }}, - {{ duration.hours }} {{ $t('decay.hours') }}, - {{ duration.minutes }} {{ $t('decay.minutes') }}, - {{ duration.seconds }} {{ $t('decay.seconds') }} - -
- {{ $t('decay.decay') }}: - {{ decay ? decay.balance + ' GDD' : '' }} -
From 019b0304652ce454c86cd7bb7743dbf31e23c49c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 8 Jul 2021 17:52:21 +0200 Subject: [PATCH 65/71] fix: Infinite Loop in Transaction List --- frontend/src/components/DecayInformation.vue | 74 +++++++++++--------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue index 75bda0a18..3b7a939c5 100644 --- a/frontend/src/components/DecayInformation.vue +++ b/frontend/src/components/DecayInformation.vue @@ -39,14 +39,20 @@
{{ $t('decay.since_introduction') }}
- {{ getDuration(decay.decay_end, decay.decay_start) }} - - {{ duration.years }} {{ $t('decay.year') }}, - {{ duration.months }} {{ $t('decay.months') }}, - {{ duration.days }} {{ $t('decay.days') }}, - {{ duration.hours }} {{ $t('decay.hours') }}, - {{ duration.minutes }} {{ $t('decay.minutes') }}, - {{ duration.seconds }} {{ $t('decay.seconds') }} + {{ getDuration }} + + {{ getDuration.years }} {{ $t('decay.year') }}, + + {{ getDuration.months }} {{ $t('decay.months') }}, + + {{ getDuration.days }} {{ $t('decay.days') }}, + {{ getDuration.hours }} {{ $t('decay.hours') }}, + + {{ getDuration.minutes }} {{ $t('decay.minutes') }}, + + + {{ getDuration.seconds }} {{ $t('decay.seconds') }} +
@@ -56,30 +62,30 @@ From bb91b8a269cbcc620823b8af485434ce417c8674 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 8 Jul 2021 18:01:49 +0200 Subject: [PATCH 66/71] fix duration calculation --- frontend/src/components/DecayInformation.vue | 25 +++++++------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue index 3b7a939c5..5179b9df1 100644 --- a/frontend/src/components/DecayInformation.vue +++ b/frontend/src/components/DecayInformation.vue @@ -39,20 +39,13 @@
{{ $t('decay.since_introduction') }}
- {{ getDuration }} - - {{ getDuration.years }} {{ $t('decay.year') }}, - - {{ getDuration.months }} {{ $t('decay.months') }}, - - {{ getDuration.days }} {{ $t('decay.days') }}, - {{ getDuration.hours }} {{ $t('decay.hours') }}, - - {{ getDuration.minutes }} {{ $t('decay.minutes') }}, - - - {{ getDuration.seconds }} {{ $t('decay.seconds') }} - + + {{ duration.years }} {{ $t('decay.year') }}, + {{ duration.months }} {{ $t('decay.months') }}, + {{ duration.days }} {{ $t('decay.days') }}, + {{ duration.hours }} {{ $t('decay.hours') }}, + {{ duration.minutes }} {{ $t('decay.minutes') }}, + {{ duration.seconds }} {{ $t('decay.seconds') }}
@@ -80,10 +73,10 @@ export default { ? ' - Startblock Decay am: ' + this.$d(this.$moment.unix(this.decay.decay_start_block)) : '' }, - getDuration() { + duration() { const startDate = this.$moment.unix(new Date(this.decay.decay_start)) const endDate = this.$moment.unix(new Date(this.decay.decay_end)) - const diff = this.$moment.duration(startDate.diff(endDate)) + const diff = this.$moment.duration(endDate.diff(startDate)) return diff._data }, }, From 1b6f91ea482ae57c45889093f8a28d1c46494dd0 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 8 Jul 2021 18:13:38 +0200 Subject: [PATCH 67/71] duration function more compact --- frontend/src/components/DecayInformation.vue | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/DecayInformation.vue b/frontend/src/components/DecayInformation.vue index 5179b9df1..c3f07c87b 100644 --- a/frontend/src/components/DecayInformation.vue +++ b/frontend/src/components/DecayInformation.vue @@ -74,10 +74,11 @@ export default { : '' }, duration() { - const startDate = this.$moment.unix(new Date(this.decay.decay_start)) - const endDate = this.$moment.unix(new Date(this.decay.decay_end)) - const diff = this.$moment.duration(endDate.diff(startDate)) - return diff._data + return this.$moment.duration( + this.$moment + .unix(new Date(this.decay.decay_end)) + .diff(this.$moment.unix(new Date(this.decay.decay_start))), + )._data }, }, } From f91ef8f5c9b0a02bf559b18109da75b84c21a463 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 8 Jul 2021 19:04:06 +0200 Subject: [PATCH 68/71] fix: QRCode Error after Logout --- frontend/src/views/Layout/DashboardLayout_gdd.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.vue b/frontend/src/views/Layout/DashboardLayout_gdd.vue index 9990b91f2..bf0385400 100755 --- a/frontend/src/views/Layout/DashboardLayout_gdd.vue +++ b/frontend/src/views/Layout/DashboardLayout_gdd.vue @@ -34,7 +34,11 @@ - + From c3457b409b06dbe1aa427f3f4082dc4523c1656b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 12 Jul 2021 11:11:54 +0200 Subject: [PATCH 69/71] feat: Test UserProfileTransactionList --- .../Pages/UserProfileTransactionList.spec.js | 33 +++++++++++++++++++ .../Pages/UserProfileTransactionList.vue | 3 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 frontend/src/views/Pages/UserProfileTransactionList.spec.js diff --git a/frontend/src/views/Pages/UserProfileTransactionList.spec.js b/frontend/src/views/Pages/UserProfileTransactionList.spec.js new file mode 100644 index 000000000..b075b2381 --- /dev/null +++ b/frontend/src/views/Pages/UserProfileTransactionList.spec.js @@ -0,0 +1,33 @@ +import { mount } from '@vue/test-utils' +import UserProfileTransactionList from './UserProfileTransactionList' + +const localVue = global.localVue + +describe('UserProfileTransactionList', () => { + let wrapper + + const mocks = { + $t: jest.fn((t) => t), + } + + const Wrapper = () => { + return mount(UserProfileTransactionList, { localVue, mocks }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders the transaction table', () => { + expect(wrapper.findComponent({ name: 'GddTransactionList' }).exists()).toBeTruthy() + }) + + it('emist update-transactions when update-transactions is called', async () => { + wrapper.findComponent({ name: 'GddTransactionList' }).vm.$emit('update-transactions') + expect(wrapper.emitted('update-transactions')).toEqual( + expect.arrayContaining([expect.arrayContaining([{ firstPage: 1, items: 25 }])]), + ) + }) + }) +}) diff --git a/frontend/src/views/Pages/UserProfileTransactionList.vue b/frontend/src/views/Pages/UserProfileTransactionList.vue index f1896acc7..e6a25b436 100644 --- a/frontend/src/views/Pages/UserProfileTransactionList.vue +++ b/frontend/src/views/Pages/UserProfileTransactionList.vue @@ -19,12 +19,13 @@ import GddTransactionList from './AccountOverview/GddTransactionList.vue' export default { + name: 'UserProfileTransactionList', components: { GddTransactionList, }, props: { transactions: { - default: [], + default: () => [], }, transactionCount: { type: Number, default: 0 }, }, From 2c74574f240a4d175ecc2f97ec39a98239bc3f69 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 12 Jul 2021 11:16:56 +0200 Subject: [PATCH 70/71] test emit of update-transaction after creation --- .../views/Pages/UserProfileTransactionList.spec.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/Pages/UserProfileTransactionList.spec.js b/frontend/src/views/Pages/UserProfileTransactionList.spec.js index b075b2381..0761c5032 100644 --- a/frontend/src/views/Pages/UserProfileTransactionList.spec.js +++ b/frontend/src/views/Pages/UserProfileTransactionList.spec.js @@ -23,11 +23,19 @@ describe('UserProfileTransactionList', () => { expect(wrapper.findComponent({ name: 'GddTransactionList' }).exists()).toBeTruthy() }) - it('emist update-transactions when update-transactions is called', async () => { - wrapper.findComponent({ name: 'GddTransactionList' }).vm.$emit('update-transactions') + it('emits update-transactions after creation', () => { expect(wrapper.emitted('update-transactions')).toEqual( expect.arrayContaining([expect.arrayContaining([{ firstPage: 1, items: 25 }])]), ) }) + + it('emist update-transactions when update-transactions is called', () => { + wrapper + .findComponent({ name: 'GddTransactionList' }) + .vm.$emit('update-transactions', { firstPage: 2, items: 25 }) + expect(wrapper.emitted('update-transactions')).toEqual( + expect.arrayContaining([expect.arrayContaining([{ firstPage: 2, items: 25 }])]), + ) + }) }) }) From 89bf681f48cb422bc2bb24913c2800dbf64a75b8 Mon Sep 17 00:00:00 2001 From: Dario Rekowski on RockPI Date: Tue, 13 Jul 2021 13:18:24 +0000 Subject: [PATCH 71/71] check if type is set --- .../AppRequests/list_transactions.ctp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/community_server/src/Template/AppRequests/list_transactions.ctp b/community_server/src/Template/AppRequests/list_transactions.ctp index f978e2e31..174092273 100644 --- a/community_server/src/Template/AppRequests/list_transactions.ctp +++ b/community_server/src/Template/AppRequests/list_transactions.ctp @@ -12,15 +12,19 @@ $body['gdtSum'] = $this->element('centToFloat', ['cent' => $body['gdtSum'], 'pre foreach($body['transactions'] as $i => $transaction) { $useCeil = false; - if($transaction['type'] == 'decay') { - $useCeil = true; - } - $body['transactions'][$i]['balance'] = $this->element('centToFloat', ['cent' => $transaction['balance'], 'precision' => 4, 'useCeil' => $useCeil]); - if(isset($transaction['creation_amount'])) { - $body['transactions'][$i]['creation_amount'] = $this->element('centToFloat', ['cent' => $transaction['creation_amount'], 'precision' => 4]); - } - if(isset($transaction['decay'])) { - $body['transactions'][$i]['decay']['balance'] = $this->element('centToFloat', ['cent' => $transaction['decay']['balance'], 'precision' => 4]); + if(!isset($transaction['type'])) { + $body = ['state' => 'error', 'msg' => 'transaction without type found', 'details' => $transaction]; + } else { + if($transaction['type'] == 'decay') { + $useCeil = true; + } + $body['transactions'][$i]['balance'] = $this->element('centToFloat', ['cent' => $transaction['balance'], 'precision' => 4, 'useCeil' => $useCeil]); + if(isset($transaction['creation_amount'])) { + $body['transactions'][$i]['creation_amount'] = $this->element('centToFloat', ['cent' => $transaction['creation_amount'], 'precision' => 4]); + } + if(isset($transaction['decay'])) { + $body['transactions'][$i]['decay']['balance'] = $this->element('centToFloat', ['cent' => $transaction['decay']['balance'], 'precision' => 4]); + } } }