mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into improve-apollo-logging
This commit is contained in:
commit
a4ae5324d5
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@ -28,7 +28,9 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
|
||||
*/
|
||||
|
||||
// rename `state_user_id` to `user_id`
|
||||
await queryFn('ALTER TABLE `state_user_transactions` RENAME COLUMN state_user_id TO user_id;')
|
||||
await queryFn(
|
||||
'ALTER TABLE `state_user_transactions` CHANGE COLUMN state_user_id user_id int(10);',
|
||||
)
|
||||
// Create new `amount` column, with a temporary default of null
|
||||
await queryFn(
|
||||
'ALTER TABLE `state_user_transactions` ADD COLUMN `amount` bigint(20) DEFAULT NULL AFTER `transaction_type_id`;',
|
||||
@ -214,5 +216,7 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom
|
||||
await queryFn('ALTER TABLE `state_user_transactions` DROP COLUMN `memo`;')
|
||||
await queryFn('ALTER TABLE `state_user_transactions` DROP COLUMN `send_sender_final_balance`;')
|
||||
await queryFn('ALTER TABLE `state_user_transactions` DROP COLUMN `amount`;')
|
||||
await queryFn('ALTER TABLE `state_user_transactions` RENAME COLUMN user_id TO state_user_id;')
|
||||
await queryFn(
|
||||
'ALTER TABLE `state_user_transactions` CHANGE COLUMN user_id state_user_id int(10);',
|
||||
)
|
||||
}
|
||||
|
||||
@ -11,23 +11,23 @@
|
||||
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
// drop column `transaction_id`, it is not needed
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `transaction_id`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `transaction_id`;')
|
||||
// drop column `received`, it is a duplicate of balance_date
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `received`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `received`;')
|
||||
// drop column `tx_hash`, it is not needed
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `tx_hash`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `tx_hash`;')
|
||||
// drop column `signature`, it is not needed
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `signature`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `signature`;')
|
||||
// drop column `pubkey`, it is not needed
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `pubkey`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `pubkey`;')
|
||||
// drop column `creation_ident_hash`, it is not needed
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `creation_ident_hash`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `creation_ident_hash`;')
|
||||
|
||||
// rename `transaction_type_id` to `type_id`
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN transaction_type_id TO type_id;')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN transaction_type_id type_id int(10);')
|
||||
// rename `linked_state_user_transaction_id` to `linked_transaction_id`
|
||||
await queryFn(
|
||||
'ALTER TABLE `transactions` RENAME COLUMN linked_state_user_transaction_id TO linked_transaction_id;',
|
||||
'ALTER TABLE `transactions` CHANGE COLUMN linked_state_user_transaction_id linked_transaction_id int(10);',
|
||||
)
|
||||
}
|
||||
|
||||
@ -41,9 +41,9 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom
|
||||
// - creation_ident_hash (null)
|
||||
|
||||
await queryFn(
|
||||
'ALTER TABLE `transactions` RENAME COLUMN linked_transaction_id TO linked_state_user_transaction_id;',
|
||||
'ALTER TABLE `transactions` CHANGE COLUMN linked_transaction_id linked_state_user_transaction_id int(10);',
|
||||
)
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN type_id TO transaction_type_id;')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN type_id transaction_type_id int(10);')
|
||||
await queryFn(
|
||||
'ALTER TABLE `transactions` ADD COLUMN `creation_ident_hash` binary(32) DEFAULT NULL AFTER `linked_state_user_transaction_id`;',
|
||||
)
|
||||
|
||||
@ -13,35 +13,39 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
|
||||
// Delete columns
|
||||
|
||||
// delete column `amount`
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `amount`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `amount`;')
|
||||
// delete column `send_sender_final_balance`
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `send_sender_final_balance`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `send_sender_final_balance`;')
|
||||
// delete column `balance`
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `balance`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `balance`;')
|
||||
// delete column `temp_dec_send_sender_final_balance`
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `temp_dec_send_sender_final_balance`;')
|
||||
await queryFn(
|
||||
'ALTER TABLE `transactions` DROP COLUMN IF EXISTS `temp_dec_send_sender_final_balance`;',
|
||||
)
|
||||
// delete column `temp_dec_diff_send_sender_final_balance`
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `temp_dec_diff_send_sender_final_balance`;')
|
||||
await queryFn(
|
||||
'ALTER TABLE `transactions` DROP COLUMN IF EXISTS `temp_dec_diff_send_sender_final_balance`;',
|
||||
)
|
||||
// delete column `temp_dec_old_balance`
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `temp_dec_old_balance`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `temp_dec_old_balance`;')
|
||||
// delete column `temp_dec_diff_balance`
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `temp_dec_diff_balance`;')
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN IF EXISTS `temp_dec_diff_balance`;')
|
||||
|
||||
// Rename columns
|
||||
|
||||
// rename column `dec_amount` to `amount`
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN `dec_amount` to `amount`;')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN `dec_amount` `amount` DECIMAL(40,20);')
|
||||
|
||||
// rename column `dec_balance` to `balance`
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN `dec_balance` to `balance`;')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN `dec_balance` `balance` DECIMAL(40,20);')
|
||||
|
||||
// rename column `dec_decay` to `decay`
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN `dec_decay` to `decay`;')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN `dec_decay` `decay` DECIMAL(40,20);')
|
||||
|
||||
// Drop tables
|
||||
|
||||
// drop `state_balances`
|
||||
await queryFn('DROP TABLE `state_balances`;')
|
||||
await queryFn('DROP TABLE IF EXISTS `state_balances`;')
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
@ -66,9 +70,9 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom
|
||||
LEFT JOIN transactions ON t.uid = transactions.user_id AND t.date = transactions.balance_date;
|
||||
`)
|
||||
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN `decay` to `dec_decay`;')
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN `balance` to `dec_balance`;')
|
||||
await queryFn('ALTER TABLE `transactions` RENAME COLUMN `amount` to `dec_amount`;')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN `decay` `dec_decay` DECIMAL(40,20);')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN `balance` `dec_balance` DECIMAL(40,20);')
|
||||
await queryFn('ALTER TABLE `transactions` CHANGE COLUMN `amount` `dec_amount` DECIMAL(40,20);')
|
||||
|
||||
await queryFn(
|
||||
'ALTER TABLE `transactions` ADD COLUMN `temp_dec_diff_balance` decimal(40,20) DEFAULT NULL AFTER linked_transaction_id;',
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
// rename `amount` to `amount_bigint`
|
||||
await queryFn('ALTER TABLE `admin_pending_creations` RENAME COLUMN `amount` TO `amount_bigint`;')
|
||||
await queryFn(
|
||||
'ALTER TABLE `admin_pending_creations` CHANGE COLUMN `amount` `amount_bigint` bigint(20);',
|
||||
)
|
||||
// add `amount` (decimal)
|
||||
await queryFn(
|
||||
'ALTER TABLE `admin_pending_creations` ADD COLUMN `amount` DECIMAL(40,20) DEFAULT NULL AFTER `amount_bigint`;',
|
||||
@ -37,6 +39,8 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom
|
||||
await queryFn(
|
||||
'ALTER TABLE `admin_pending_creations` MODIFY COLUMN `amount_bigint` bigint(20) NOT NULL;',
|
||||
)
|
||||
await queryFn('ALTER TABLE `admin_pending_creations` DROP COLUMN `amount`;')
|
||||
await queryFn('ALTER TABLE `admin_pending_creations` RENAME COLUMN `amount_bigint` TO `amount`;')
|
||||
await queryFn('ALTER TABLE `admin_pending_creations` DROP COLUMN IF EXISTS `amount`;')
|
||||
await queryFn(
|
||||
'ALTER TABLE `admin_pending_creations` CHANGE COLUMN `amount_bigint` `amount` bigint(20);',
|
||||
)
|
||||
}
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
# This assums you have root access via ssh to your cleanly setup server
|
||||
# Furthermore this assumes you have debian (11 64bit) running
|
||||
|
||||
# Check your (Sub-)Domain with your Provider.
|
||||
# In this document gddhost.tld refers to your chosen domain
|
||||
|
||||
> ssh root@gddhost.tld
|
||||
|
||||
# change root default shell
|
||||
@ -87,9 +90,10 @@
|
||||
|
||||
# Adjust .env
|
||||
# NOTE ';' can not be part of any value
|
||||
# The Github Secret is Created on Github in Settimgs -> Webhooks
|
||||
> cd gradido/deployment/bare_metal
|
||||
> cp .env.dist .env
|
||||
> nano .env
|
||||
>> Adjust values accordingly
|
||||
# TODO the install.sh is not yet ready to run directly - consider to use it as pattern to do it manually
|
||||
> ./install.sh
|
||||
> ./install.sh
|
||||
|
||||
@ -105,8 +105,7 @@ yarn install
|
||||
yarn build
|
||||
if [ "$DEPLOY_SEED_DATA" = "true" ]; then
|
||||
yarn dev_up
|
||||
# As dev_reset is not running properly (0019-replace_login_user_id_with_state_user_id)
|
||||
# yarn dev_reset
|
||||
yarn dev_reset
|
||||
else
|
||||
yarn up
|
||||
fi
|
||||
|
||||
63
frontend/src/components/Message/Message.spec.js
Normal file
63
frontend/src/components/Message/Message.spec.js
Normal file
@ -0,0 +1,63 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Message from './Message'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const propsData = {
|
||||
headline: 'site.thx.title',
|
||||
subtitle: 'site.thx.email',
|
||||
buttonText: 'login',
|
||||
linkTo: '/login',
|
||||
}
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
}
|
||||
|
||||
describe('Message', () => {
|
||||
let wrapper
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(Message, { localVue, mocks, propsData })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div.header').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('with button', () => {
|
||||
it('renders title, subtitle, and button text', () => {
|
||||
expect(wrapper.find('.test-message-headline').text()).toBe('site.thx.title')
|
||||
expect(wrapper.find('.test-message-subtitle').text()).toBe('site.thx.email')
|
||||
expect(wrapper.find('.test-message-button').text()).toBe('login')
|
||||
})
|
||||
|
||||
it('button link redirects to /login', () => {
|
||||
expect(wrapper.find('a.btn').attributes('href')).toBe('/login')
|
||||
})
|
||||
})
|
||||
|
||||
describe('without button', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.setProps({
|
||||
buttonText: null,
|
||||
linkTo: null,
|
||||
})
|
||||
})
|
||||
|
||||
it('renders title, subtitle, and button text', () => {
|
||||
expect(wrapper.find('.test-message-headline').text()).toBe('site.thx.title')
|
||||
expect(wrapper.find('.test-message-subtitle').text()).toBe('site.thx.email')
|
||||
})
|
||||
|
||||
it('button is not shown', () => {
|
||||
expect(wrapper.find('.test-message-button').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
36
frontend/src/components/Message/Message.vue
Normal file
36
frontend/src/components/Message/Message.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="header py-lg-6">
|
||||
<b-container class="w-50">
|
||||
<div class="header-body text-center mb-7">
|
||||
<p class="h1 test-message-headline">{{ headline }}</p>
|
||||
<p class="h4 test-message-subtitle">{{ subtitle }}</p>
|
||||
<hr />
|
||||
<b-button v-if="showButton" class="test-message-button" :to="buttonLinkTo">
|
||||
{{ buttonText }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Message',
|
||||
props: {
|
||||
headline: { type: String, required: true },
|
||||
subtitle: { type: String, required: true },
|
||||
buttonText: { type: String, required: false, default: null },
|
||||
linkTo: { type: String, required: false, default: null },
|
||||
},
|
||||
computed: {
|
||||
showButton() {
|
||||
return this.buttonText && this.linkTo
|
||||
},
|
||||
buttonLinkTo() {
|
||||
return this.linkTo ? this.linkTo : null
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -227,6 +227,36 @@ describe('TransactionLinkSummary', () => {
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
})
|
||||
|
||||
describe('close transaction link list', () => {
|
||||
beforeEach(async () => {
|
||||
wrapper.find('div.transaction-link-details').trigger('click')
|
||||
})
|
||||
describe('reopen transaction link list', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
wrapper.find('div.transaction-link-details').trigger('click')
|
||||
})
|
||||
|
||||
it('calls the API once', () => {
|
||||
expect(apolloQueryMock).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it('calls the API with current page one', () => {
|
||||
expect(apolloQueryMock).toBeCalledWith({
|
||||
query: listTransactionLinks,
|
||||
variables: {
|
||||
currentPage: 1,
|
||||
},
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
})
|
||||
|
||||
it('has four transactionLinks', () => {
|
||||
expect(wrapper.vm.transactionLinks).toHaveLength(4)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -84,7 +84,11 @@ export default {
|
||||
this.visible = false
|
||||
} else {
|
||||
this.transactionLinks = []
|
||||
this.updateListTransactionLinks()
|
||||
if (this.currentPage === 1) {
|
||||
this.updateListTransactionLinks()
|
||||
} else {
|
||||
this.currentPage = 1
|
||||
}
|
||||
this.visible = true
|
||||
}
|
||||
},
|
||||
|
||||
@ -33,9 +33,12 @@
|
||||
"email-already-sent": "Wir haben dir bereits eine E-Mail vor weniger als 10 Minuten geschickt.",
|
||||
"empty-transactionlist": "Es gab einen Fehler mit der Übermittlung der Anzahl deiner Transaktionen.",
|
||||
"error": "Fehler!",
|
||||
"no-account": "Leider konnten wir keinen Account mit diesen Daten finden.",
|
||||
"no-transactionlist": "Es gab leider einen Fehler. Es wurden keine Transaktionen vom Server übermittelt",
|
||||
"session-expired": "Die Sitzung wurde aus Sicherheitsgründen beendet."
|
||||
"no-account": "Leider konnten wir keinen (aktivierten) Account mit diesen Daten finden.",
|
||||
"no-transactionlist": "Es gab leider einen Fehler. Es wurden keine Transaktionen vom Server übermittelt.",
|
||||
"no-user": "Kein Benutzer mit diesen Anmeldedaten.",
|
||||
"session-expired": "Die Sitzung wurde aus Sicherheitsgründen beendet.",
|
||||
"unknown-error": "Unbekanter Fehler: ",
|
||||
"user-already-exists": "Ein Benutzer mit diesen Daten existiert bereits."
|
||||
},
|
||||
"footer": {
|
||||
"app_version": "App version {version}",
|
||||
@ -234,7 +237,8 @@
|
||||
"register": "Du bist jetzt registriert, bitte überprüfe deine Emails und klicke auf den Aktivierungslink.",
|
||||
"reset": "Dein Passwort wurde geändert.",
|
||||
"resetPassword": "Den Code den Du genutzt hast ist zu alt bitte fordere ein neuen über die Passwort Reset Seite an.",
|
||||
"title": "Danke!"
|
||||
"title": "Danke!",
|
||||
"unsetPassword": "Dein Passwort wurde noch nicht gesetzt. Bitte setze es neu."
|
||||
}
|
||||
},
|
||||
"success": "Erfolg",
|
||||
|
||||
@ -33,9 +33,12 @@
|
||||
"email-already-sent": "We already sent you an email less than 10 minutes ago.",
|
||||
"empty-transactionlist": "There was an error with the transmission of the number of your transactions.",
|
||||
"error": "Error!",
|
||||
"no-account": "Unfortunately we could not find an account to the given data!",
|
||||
"no-account": "Unfortunately we could not find an (activated) account to the given data.",
|
||||
"no-transactionlist": "Unfortunately, there was an error. No transactions have been sent from the server.",
|
||||
"session-expired": "The session was closed for security reasons."
|
||||
"no-user": "No user with this credentials.",
|
||||
"session-expired": "The session was closed for security reasons.",
|
||||
"unknown-error": "Unknown error: ",
|
||||
"user-already-exists": "A user with this data already exists."
|
||||
},
|
||||
"footer": {
|
||||
"app_version": "App version {version}",
|
||||
@ -226,7 +229,7 @@
|
||||
"uppercase": "One uppercase letter required."
|
||||
},
|
||||
"thx": {
|
||||
"activateEmail": "Your account has not been activated yet, please check your emails and click the activation link or order a new activation link over the password reset page.",
|
||||
"activateEmail": "Your account has not been activated yet. Please check your emails and click the activation link or order a new activation link over the password reset page.",
|
||||
"checkEmail": "Your email has been successfully verified. You can sign in now.",
|
||||
"email": "We have sent you an email.",
|
||||
"emailActivated": "Thank you your email has been activated.",
|
||||
@ -234,7 +237,8 @@
|
||||
"register": "You are registered now, please check your emails and click the activation link.",
|
||||
"reset": "Your password has been changed.",
|
||||
"resetPassword": "The code you used was to old please order a new on over the password reset page.",
|
||||
"title": "Thank you!"
|
||||
"title": "Thank you!",
|
||||
"unsetPassword": "Your password has not been set yet. Please set it again."
|
||||
}
|
||||
},
|
||||
"success": "Success",
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||
import flushPromises from 'flush-promises'
|
||||
import ForgotPassword from './ForgotPassword'
|
||||
|
||||
import { toastErrorSpy } from '@test/testSetup'
|
||||
import ForgotPassword from './ForgotPassword'
|
||||
|
||||
const mockAPIcall = jest.fn()
|
||||
|
||||
@ -48,7 +47,7 @@ describe('ForgotPassword', () => {
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div.forgot-password').exists()).toBeTruthy()
|
||||
expect(wrapper.find('div.forgot-password').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has a title', () => {
|
||||
@ -85,7 +84,7 @@ describe('ForgotPassword', () => {
|
||||
})
|
||||
|
||||
it('has a submit button', () => {
|
||||
expect(form.find('button[type="submit"]').exists()).toBeTruthy()
|
||||
expect(form.find('button[type="submit"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('invalid Email', () => {
|
||||
@ -118,19 +117,25 @@ describe('ForgotPassword', () => {
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('toasts a standard error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.email-already-sent')
|
||||
it('shows error title, subtitle, login button', () => {
|
||||
expect(wrapper.vm.showPageMessage).toBe(true)
|
||||
expect(wrapper.find('.test-message-headline').text()).toBe('site.thx.errorTitle')
|
||||
expect(wrapper.find('.test-message-subtitle').text()).toBe('error.email-already-sent')
|
||||
expect(wrapper.find('.test-message-button').text()).toBe('login')
|
||||
})
|
||||
|
||||
it('pushes to "/thx/forgotPassword"', () => {
|
||||
expect(mockAPIcall).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
email: 'user@example.org',
|
||||
},
|
||||
}),
|
||||
)
|
||||
expect(mockRouterPush).toHaveBeenCalledWith('/thx/forgotPassword')
|
||||
it('button link directs to "/login"', () => {
|
||||
expect(wrapper.find('.test-message-button').attributes('href')).toBe('/login')
|
||||
})
|
||||
|
||||
it.skip('click redirects to "/login"', async () => {
|
||||
// wrapper.find('.test-message-button').trigger('click')
|
||||
// await wrapper.vm.$nextTick()
|
||||
expect(mockRouterPush).toBeCalledWith('/login')
|
||||
})
|
||||
|
||||
it('toasts a standard error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.email-already-sent')
|
||||
})
|
||||
})
|
||||
|
||||
@ -147,15 +152,19 @@ describe('ForgotPassword', () => {
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('pushes to "/thx/forgotPassword"', () => {
|
||||
expect(mockAPIcall).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
email: 'user@example.org',
|
||||
},
|
||||
}),
|
||||
)
|
||||
expect(mockRouterPush).toHaveBeenCalledWith('/thx/forgotPassword')
|
||||
it('shows success title, subtitle, login button', () => {
|
||||
expect(wrapper.vm.showPageMessage).toBe(true)
|
||||
expect(wrapper.find('.test-message-headline').text()).toBe('site.thx.title')
|
||||
expect(wrapper.find('.test-message-subtitle').text()).toBe('site.thx.email')
|
||||
expect(wrapper.find('.test-message-button').text()).toBe('login')
|
||||
})
|
||||
|
||||
it('button link redirects to "/login"', () => {
|
||||
expect(wrapper.find('.test-message-button').attributes('href')).toBe('/login')
|
||||
})
|
||||
|
||||
it.skip('click redirects to "/login"', () => {
|
||||
// expect(mockRouterPush).toBeCalledWith('/login')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
<b-container class="mt--8 p-1">
|
||||
<b-container v-if="enterData" class="mt--8 p-1">
|
||||
<b-row class="justify-content-center">
|
||||
<b-col lg="6" md="8">
|
||||
<b-card no-body class="border-0 gradido-custom-background">
|
||||
@ -36,24 +36,48 @@
|
||||
<router-link to="/login" class="mt-3">{{ $t('back') }}</router-link>
|
||||
</div>
|
||||
</b-container>
|
||||
<b-container v-else class="mt--8 p-1">
|
||||
<message
|
||||
v-if="success"
|
||||
:headline="$t('site.thx.title')"
|
||||
:subtitle="$t('site.thx.email')"
|
||||
:buttonText="$t('login')"
|
||||
linkTo="/login"
|
||||
/>
|
||||
<message
|
||||
v-else
|
||||
:headline="$t('site.thx.errorTitle')"
|
||||
:subtitle="$t('error.email-already-sent')"
|
||||
:buttonText="$t('login')"
|
||||
linkTo="/login"
|
||||
/>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { forgotPassword } from '@/graphql/mutations'
|
||||
import InputEmail from '@/components/Inputs/InputEmail'
|
||||
import Message from '@/components/Message/Message'
|
||||
|
||||
export default {
|
||||
name: 'ForgotPassword',
|
||||
components: {
|
||||
InputEmail,
|
||||
Message,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disable: 'disabled',
|
||||
form: {
|
||||
email: '',
|
||||
},
|
||||
subtitle: 'settings.password.subtitle',
|
||||
showPageMessage: false,
|
||||
success: null,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.$route.params.comingFrom) {
|
||||
this.subtitle = 'settings.password.resend_subtitle'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -66,18 +90,20 @@ export default {
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.$router.push('/thx/forgotPassword')
|
||||
this.showPageMessage = true
|
||||
this.success = true
|
||||
})
|
||||
.catch(() => {
|
||||
this.showPageMessage = true
|
||||
this.success = false
|
||||
this.toastError(this.$t('error.email-already-sent'))
|
||||
this.$router.push('/thx/forgotPassword')
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.$route.params.comingFrom) {
|
||||
this.subtitle = 'settings.password.resend_subtitle'
|
||||
}
|
||||
computed: {
|
||||
enterData() {
|
||||
return !this.showPageMessage
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { RouterLinkStub, mount } from '@vue/test-utils'
|
||||
import flushPromises from 'flush-promises'
|
||||
import Login from './Login'
|
||||
|
||||
import { toastErrorSpy } from '@test/testSetup'
|
||||
import Login from './Login'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
@ -60,7 +59,7 @@ describe('Login', () => {
|
||||
})
|
||||
|
||||
it('renders the Login form', () => {
|
||||
expect(wrapper.find('div.login-form').exists()).toBeTruthy()
|
||||
expect(wrapper.find('div.login-form').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('Login header', () => {
|
||||
@ -103,19 +102,19 @@ describe('Login', () => {
|
||||
|
||||
describe('Login form', () => {
|
||||
it('has a login form', () => {
|
||||
expect(wrapper.find('form').exists()).toBeTruthy()
|
||||
expect(wrapper.find('form').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has an Email input field', () => {
|
||||
expect(wrapper.find('input[placeholder="Email"]').exists()).toBeTruthy()
|
||||
expect(wrapper.find('input[placeholder="Email"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has an Password input field', () => {
|
||||
expect(wrapper.find('input[placeholder="form.password"]').exists()).toBeTruthy()
|
||||
expect(wrapper.find('input[placeholder="form.password"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has a Submit button', () => {
|
||||
expect(wrapper.find('button[type="submit"]').exists()).toBeTruthy()
|
||||
expect(wrapper.find('button[type="submit"]').exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@ -205,61 +204,111 @@ describe('Login', () => {
|
||||
})
|
||||
|
||||
describe('login fails', () => {
|
||||
beforeEach(async () => {
|
||||
const createError = async (errorMessage) => {
|
||||
apolloQueryMock.mockRejectedValue({
|
||||
message: errorMessage,
|
||||
})
|
||||
wrapper = Wrapper()
|
||||
jest.clearAllMocks()
|
||||
await wrapper.find('input[placeholder="Email"]').setValue('user@example.org')
|
||||
await wrapper.find('input[placeholder="form.password"]').setValue('1234')
|
||||
await flushPromises()
|
||||
apolloQueryMock.mockRejectedValue({
|
||||
message: '..No user with this credentials',
|
||||
})
|
||||
await wrapper.find('form').trigger('submit')
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('hides the spinner', () => {
|
||||
expect(spinnerHideMock).toBeCalled()
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.no-account')
|
||||
})
|
||||
}
|
||||
|
||||
describe('login fails with "User email not validated"', () => {
|
||||
beforeEach(async () => {
|
||||
apolloQueryMock.mockRejectedValue({
|
||||
message: 'User email not validated',
|
||||
})
|
||||
wrapper = Wrapper()
|
||||
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()
|
||||
await createError('GraphQL error: User email not validated.')
|
||||
})
|
||||
|
||||
it('redirects to /thx/login', () => {
|
||||
expect(mockRouterPush).toBeCalledWith('/thx/login')
|
||||
it('hides the spinner', () => {
|
||||
expect(spinnerHideMock).toBeCalled()
|
||||
})
|
||||
|
||||
it('shows error title, subtitle, login button', () => {
|
||||
expect(wrapper.vm.showPageMessage).toBe(true)
|
||||
expect(wrapper.find('.test-message-headline').text()).toBe('site.thx.errorTitle')
|
||||
expect(wrapper.find('.test-message-subtitle').text()).toBe('site.thx.activateEmail')
|
||||
expect(wrapper.find('.test-message-button').text()).toBe('settings.password.reset')
|
||||
})
|
||||
|
||||
it('button link directs to "/forgot-password"', () => {
|
||||
expect(wrapper.find('.test-message-button').attributes('href')).toBe('/forgot-password')
|
||||
})
|
||||
|
||||
it.skip('click redirects to "/forgot-password"', async () => {
|
||||
// wrapper.find('.test-message-button').trigger('click')
|
||||
// await flushPromises()
|
||||
// await wrapper.vm.$nextTick()
|
||||
// expect(mockRouterPush).toBeCalledWith('/forgot-password')
|
||||
})
|
||||
|
||||
it('toasts the error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.no-account')
|
||||
})
|
||||
})
|
||||
|
||||
describe('login fails with "User has no password set yet"', () => {
|
||||
beforeEach(async () => {
|
||||
apolloQueryMock.mockRejectedValue({
|
||||
message: 'User has no password set yet',
|
||||
})
|
||||
wrapper = Wrapper()
|
||||
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()
|
||||
await createError('GraphQL error: User has no password set yet.')
|
||||
})
|
||||
|
||||
it('redirects to /reset-password/login', () => {
|
||||
expect(mockRouterPush).toBeCalledWith('/reset-password/login')
|
||||
it('shows error title, subtitle, login button', () => {
|
||||
expect(wrapper.vm.showPageMessage).toBe(true)
|
||||
expect(wrapper.find('.test-message-headline').text()).toBe('site.thx.errorTitle')
|
||||
expect(wrapper.find('.test-message-subtitle').text()).toBe('site.thx.unsetPassword')
|
||||
expect(wrapper.find('.test-message-button').text()).toBe('settings.password.reset')
|
||||
})
|
||||
|
||||
it('button link directs to "/reset-password/login"', () => {
|
||||
expect(wrapper.find('.test-message-button').attributes('href')).toBe(
|
||||
'/reset-password/login',
|
||||
)
|
||||
})
|
||||
|
||||
it.skip('click redirects to "/reset-password/login"', () => {
|
||||
// expect(mockRouterPush).toBeCalledWith('/reset-password/login')
|
||||
})
|
||||
|
||||
it('toasts the error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.no-account')
|
||||
})
|
||||
})
|
||||
|
||||
describe('login fails with "No user with this credentials"', () => {
|
||||
beforeEach(async () => {
|
||||
await createError('GraphQL error: No user with this credentials.')
|
||||
})
|
||||
|
||||
it('shows no error message on the page', () => {
|
||||
// don't show any error on the page! against boots
|
||||
expect(wrapper.vm.showPageMessage).toBe(false)
|
||||
expect(wrapper.find('.test-message-headline').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-subtitle').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-button').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('toasts the error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.no-user')
|
||||
})
|
||||
})
|
||||
|
||||
describe('login fails with an unknow error', () => {
|
||||
beforeEach(async () => {
|
||||
await createError(' – Unknow error')
|
||||
})
|
||||
|
||||
it('shows no error message on the page', () => {
|
||||
// don't show any error on the page! against boots
|
||||
expect(wrapper.vm.showPageMessage).toBe(false)
|
||||
expect(wrapper.find('.test-message-headline').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-subtitle').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-button').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('toasts the error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.unknown-error – Unknow error')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
<b-container class="mt--8">
|
||||
<b-container v-if="enterData" class="mt--8 p-1">
|
||||
<b-row class="justify-content-center">
|
||||
<b-col lg="5" md="7">
|
||||
<b-card no-body class="border-0 mb-0 gradido-custom-background">
|
||||
@ -57,11 +57,21 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
<b-container v-else class="mt--8 p-1">
|
||||
<message
|
||||
:headline="$t('site.thx.errorTitle')"
|
||||
:subtitle="errorSubtitle"
|
||||
:buttonText="$t('settings.password.reset')"
|
||||
:linkTo="errorLinkTo"
|
||||
/>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import InputPassword from '@/components/Inputs/InputPassword'
|
||||
import InputEmail from '@/components/Inputs/InputEmail'
|
||||
import Message from '@/components/Message/Message'
|
||||
import { login } from '@/graphql/queries'
|
||||
import CONFIG from '@/config'
|
||||
|
||||
@ -70,6 +80,7 @@ export default {
|
||||
components: {
|
||||
InputPassword,
|
||||
InputEmail,
|
||||
Message,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -78,6 +89,10 @@ export default {
|
||||
password: '',
|
||||
},
|
||||
passwordVisible: false,
|
||||
showPageMessage: false,
|
||||
errorReason: null,
|
||||
errorSubtitle: '',
|
||||
errorLinkTo: '',
|
||||
CONFIG,
|
||||
}
|
||||
},
|
||||
@ -109,15 +124,31 @@ export default {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastError(this.$t('error.no-account'))
|
||||
if (error.message.includes('User email not validated')) {
|
||||
this.$router.push('/thx/login')
|
||||
this.showPageMessage = true
|
||||
this.errorSubtitle = this.$t('site.thx.activateEmail')
|
||||
this.errorLinkTo = '/forgot-password'
|
||||
this.toastError(this.$t('error.no-account'))
|
||||
} else if (error.message.includes('User has no password set yet')) {
|
||||
this.$router.push('/reset-password/login')
|
||||
this.showPageMessage = true
|
||||
this.errorSubtitle = this.$t('site.thx.unsetPassword')
|
||||
this.errorLinkTo = '/reset-password/login'
|
||||
this.toastError(this.$t('error.no-account'))
|
||||
} else if (error.message.includes('No user with this credentials')) {
|
||||
// don't show any error on the page! against boots
|
||||
this.toastError(this.$t('error.no-user'))
|
||||
} else {
|
||||
// don't show any error on the page! against boots
|
||||
this.toastError(this.$t('error.unknown-error') + error.message)
|
||||
}
|
||||
loader.hide()
|
||||
})
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
enterData() {
|
||||
return !this.showPageMessage
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||
import flushPromises from 'flush-promises'
|
||||
import { toastErrorSpy } from '@test/testSetup'
|
||||
import Register from './Register'
|
||||
|
||||
const localVue = global.localVue
|
||||
@ -49,7 +50,7 @@ describe('Register', () => {
|
||||
})
|
||||
|
||||
it('renders the Register form', () => {
|
||||
expect(wrapper.find('div#registerform').exists()).toBeTruthy()
|
||||
expect(wrapper.find('div#registerform').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('Register header', () => {
|
||||
@ -93,22 +94,22 @@ describe('Register', () => {
|
||||
|
||||
describe('Register form', () => {
|
||||
it('has a register form', () => {
|
||||
expect(wrapper.find('form').exists()).toBeTruthy()
|
||||
expect(wrapper.find('form').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has firstname input fields', () => {
|
||||
expect(wrapper.find('#registerFirstname').exists()).toBeTruthy()
|
||||
expect(wrapper.find('#registerFirstname').exists()).toBe(true)
|
||||
})
|
||||
it('has lastname input fields', () => {
|
||||
expect(wrapper.find('#registerLastname').exists()).toBeTruthy()
|
||||
expect(wrapper.find('#registerLastname').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has email input fields', () => {
|
||||
expect(wrapper.find('#Email-input-field').exists()).toBeTruthy()
|
||||
expect(wrapper.find('#Email-input-field').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has Language selected field', () => {
|
||||
expect(wrapper.find('.selectedLanguage').exists()).toBeTruthy()
|
||||
expect(wrapper.find('.selectedLanguage').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('selects Language value en', async () => {
|
||||
@ -117,7 +118,7 @@ describe('Register', () => {
|
||||
})
|
||||
|
||||
it('has 1 checkbox input fields', () => {
|
||||
expect(wrapper.find('#registerCheckbox').exists()).toBeTruthy()
|
||||
expect(wrapper.find('#registerCheckbox').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has PublisherId input fields', () => {
|
||||
@ -220,42 +221,63 @@ describe('Register', () => {
|
||||
})
|
||||
|
||||
describe('server sends back error', () => {
|
||||
beforeEach(async () => {
|
||||
registerUserMutationMock.mockRejectedValue({ message: 'Ouch!' })
|
||||
const createError = async (errorMessage) => {
|
||||
registerUserMutationMock.mockRejectedValue({
|
||||
message: errorMessage,
|
||||
})
|
||||
await wrapper.find('form').trigger('submit')
|
||||
await flushPromises()
|
||||
}
|
||||
|
||||
describe('server sends back error "User already exists."', () => {
|
||||
beforeEach(async () => {
|
||||
await createError('GraphQL error: User already exists.')
|
||||
})
|
||||
|
||||
it('shows no error message on the page', () => {
|
||||
// don't show any error on the page! against boots
|
||||
expect(wrapper.vm.showPageMessage).toBe(false)
|
||||
expect(wrapper.find('.test-message-headline').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-subtitle').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-button').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('toasts the error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.user-already-exists')
|
||||
})
|
||||
})
|
||||
|
||||
it('shows error message', () => {
|
||||
expect(wrapper.find('span.alert-text').exists()).toBeTruthy()
|
||||
expect(wrapper.find('span.alert-text').text().length !== 0).toBeTruthy()
|
||||
expect(wrapper.find('span.alert-text').text()).toContain('error.error')
|
||||
expect(wrapper.find('span.alert-text').text()).toContain('Ouch!')
|
||||
})
|
||||
describe('server sends back error "Unknown error"', () => {
|
||||
beforeEach(async () => {
|
||||
await createError(' – Unknown error.')
|
||||
})
|
||||
|
||||
it('button to dismisses error message is present', () => {
|
||||
expect(wrapper.find('button.close').exists()).toBeTruthy()
|
||||
})
|
||||
it('shows no error message on the page', () => {
|
||||
// don't show any error on the page! against boots
|
||||
expect(wrapper.vm.showPageMessage).toBe(false)
|
||||
expect(wrapper.find('.test-message-headline').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-subtitle').exists()).toBe(false)
|
||||
expect(wrapper.find('.test-message-button').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('dismisses error message', async () => {
|
||||
await wrapper.find('button.close').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('span.alert-text').exists()).not.toBeTruthy()
|
||||
it('toasts the error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('error.unknown-error – Unknown error.')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('server sends back success', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
registerUserMutationMock.mockResolvedValue({
|
||||
data: {
|
||||
create: 'success',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('routes to "/thx/register"', async () => {
|
||||
await wrapper.find('form').trigger('submit')
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('submit sends apollo mutate', () => {
|
||||
expect(registerUserMutationMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
@ -267,7 +289,16 @@ describe('Register', () => {
|
||||
},
|
||||
}),
|
||||
)
|
||||
expect(routerPushMock).toHaveBeenCalledWith('/thx/register')
|
||||
})
|
||||
|
||||
it('shows success title, subtitle', () => {
|
||||
expect(wrapper.vm.showPageMessage).toBe(true)
|
||||
expect(wrapper.find('.test-message-headline').text()).toBe('site.thx.title')
|
||||
expect(wrapper.find('.test-message-subtitle').text()).toBe('site.thx.register')
|
||||
})
|
||||
|
||||
it('button is not present', () => {
|
||||
expect(wrapper.find('.test-message-button').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Page content -->
|
||||
<b-container class="mt--8 p-1">
|
||||
<b-container v-if="enterData" class="mt--8 p-1">
|
||||
<!-- Table -->
|
||||
|
||||
<b-row class="justify-content-center">
|
||||
@ -105,19 +105,6 @@
|
||||
</b-form-checkbox>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-alert
|
||||
v-if="showError"
|
||||
show
|
||||
dismissible
|
||||
variant="danger"
|
||||
@dismissed="closeAlert"
|
||||
>
|
||||
<span class="alert-icon"><i class="ni ni-point"></i></span>
|
||||
<span class="alert-text">
|
||||
<strong>{{ $t('error.error') }}</strong>
|
||||
{{ messageError }}
|
||||
</span>
|
||||
</b-alert>
|
||||
|
||||
<b-row v-b-toggle:my-collapse class="text-muted shadow-sm p-3 publisherCollaps">
|
||||
<b-col>{{ $t('publisher.publisherId') }} {{ $store.state.publisherId }}</b-col>
|
||||
@ -177,6 +164,9 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
<b-container v-else class="mt--8 p-1">
|
||||
<message :headline="$t('site.thx.title')" :subtitle="$t('site.thx.register')" />
|
||||
</b-container>
|
||||
<!--
|
||||
<div class="text-center pt-4">
|
||||
<router-link class="test-button-another-community" to="/select-community">
|
||||
@ -189,13 +179,18 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import InputEmail from '@/components/Inputs/InputEmail.vue'
|
||||
import LanguageSwitchSelect from '@/components/LanguageSwitchSelect.vue'
|
||||
import { createUser } from '@/graphql/mutations'
|
||||
import CONFIG from '@/config'
|
||||
import InputEmail from '@/components/Inputs/InputEmail.vue'
|
||||
import LanguageSwitchSelect from '@/components/LanguageSwitchSelect.vue'
|
||||
import Message from '@/components/Message/Message'
|
||||
|
||||
export default {
|
||||
components: { InputEmail, LanguageSwitchSelect },
|
||||
components: {
|
||||
InputEmail,
|
||||
LanguageSwitchSelect,
|
||||
Message,
|
||||
},
|
||||
name: 'Register',
|
||||
data() {
|
||||
return {
|
||||
@ -206,10 +201,8 @@ export default {
|
||||
agree: false,
|
||||
},
|
||||
language: '',
|
||||
showPageMessage: false,
|
||||
submitted: false,
|
||||
showError: false,
|
||||
messageError: '',
|
||||
register: true,
|
||||
publisherId: this.$store.state.publisherId,
|
||||
redeemCode: this.$route.params.code,
|
||||
CONFIG,
|
||||
@ -240,20 +233,22 @@ export default {
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.$router.push('/thx/register')
|
||||
this.showPageMessage = true
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showError = true
|
||||
this.messageError = error.message
|
||||
// don't show any error on the page! against boots
|
||||
let errorMessage
|
||||
switch (error.message) {
|
||||
case 'GraphQL error: User already exists.':
|
||||
errorMessage = this.$t('error.user-already-exists')
|
||||
break
|
||||
default:
|
||||
errorMessage = this.$t('error.unknown-error') + error.message
|
||||
break
|
||||
}
|
||||
this.toastError(errorMessage)
|
||||
})
|
||||
},
|
||||
closeAlert() {
|
||||
this.showError = false
|
||||
this.messageError = ''
|
||||
this.form.email = ''
|
||||
this.form.firstname = ''
|
||||
this.form.lastname = ''
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
namesFilled() {
|
||||
@ -270,6 +265,9 @@ export default {
|
||||
disabled() {
|
||||
return !(this.namesFilled && this.emailFilled && this.form.agree && !!this.language)
|
||||
},
|
||||
enterData() {
|
||||
return !this.showPageMessage
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user