mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into refactor_arithmetic_transactionlist_adminarea
This commit is contained in:
commit
91fda4c097
@ -36,6 +36,7 @@
|
|||||||
"graphql": "^15.6.1",
|
"graphql": "^15.6.1",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "26.6.3",
|
"jest": "26.6.3",
|
||||||
|
"portal-vue": "^2.1.7",
|
||||||
"regenerator-runtime": "^0.13.9",
|
"regenerator-runtime": "^0.13.9",
|
||||||
"stats-webpack-plugin": "^0.7.0",
|
"stats-webpack-plugin": "^0.7.0",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
@ -43,7 +44,6 @@
|
|||||||
"vue-i18n": "^8.26.5",
|
"vue-i18n": "^8.26.5",
|
||||||
"vue-jest": "^3.0.7",
|
"vue-jest": "^3.0.7",
|
||||||
"vue-router": "^3.5.3",
|
"vue-router": "^3.5.3",
|
||||||
"vue-toasted": "^1.1.28",
|
|
||||||
"vuex": "^3.6.2",
|
"vuex": "^3.6.2",
|
||||||
"vuex-persistedstate": "^4.1.0"
|
"vuex-persistedstate": "^4.1.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,21 +1,17 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import ConfirmRegisterMailFormular from './ConfirmRegisterMailFormular.vue'
|
import ConfirmRegisterMailFormular from './ConfirmRegisterMailFormular.vue'
|
||||||
|
|
||||||
|
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
const apolloMutateMock = jest.fn().mockResolvedValue()
|
const apolloMutateMock = jest.fn().mockResolvedValue()
|
||||||
const toastSuccessMock = jest.fn()
|
|
||||||
const toastErrorMock = jest.fn()
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$apollo: {
|
$apollo: {
|
||||||
mutate: apolloMutateMock,
|
mutate: apolloMutateMock,
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
success: toastSuccessMock,
|
|
||||||
error: toastErrorMock,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const propsData = {
|
const propsData = {
|
||||||
@ -54,7 +50,7 @@ describe('ConfirmRegisterMailFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
it('toasts a success message', () => {
|
||||||
expect(toastSuccessMock).toBeCalledWith('unregister_mail.success')
|
expect(toastSuccessSpy).toBeCalledWith('unregister_mail.success')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -66,7 +62,7 @@ describe('ConfirmRegisterMailFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastErrorMock).toBeCalledWith('unregister_mail.error')
|
expect(toastErrorSpy).toBeCalledWith('unregister_mail.error')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -48,10 +48,10 @@ export default {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$toasted.success(this.$t('unregister_mail.success', { email: this.email }))
|
this.toastSuccess(this.$t('unregister_mail.success', { email: this.email }))
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(this.$t('unregister_mail.error', { message: error.message }))
|
this.toastError(this.$t('unregister_mail.error', { message: error.message }))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils'
|
|||||||
import CreationFormular from './CreationFormular.vue'
|
import CreationFormular from './CreationFormular.vue'
|
||||||
import { createPendingCreation } from '../graphql/createPendingCreation'
|
import { createPendingCreation } from '../graphql/createPendingCreation'
|
||||||
import { createPendingCreations } from '../graphql/createPendingCreations'
|
import { createPendingCreations } from '../graphql/createPendingCreations'
|
||||||
|
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -11,8 +12,6 @@ const apolloMutateMock = jest.fn().mockResolvedValue({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
const stateCommitMock = jest.fn()
|
const stateCommitMock = jest.fn()
|
||||||
const toastedErrorMock = jest.fn()
|
|
||||||
const toastedSuccessMock = jest.fn()
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t, options) => (options ? [t, options] : t)),
|
$t: jest.fn((t, options) => (options ? [t, options] : t)),
|
||||||
@ -32,10 +31,6 @@ const mocks = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: toastedErrorMock,
|
|
||||||
success: toastedSuccessMock,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const propsData = {
|
const propsData = {
|
||||||
@ -140,7 +135,7 @@ describe('CreationFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
it('toasts a success message', () => {
|
||||||
expect(toastedSuccessMock).toBeCalledWith([
|
expect(toastSuccessSpy).toBeCalledWith([
|
||||||
'creation_form.toasted',
|
'creation_form.toasted',
|
||||||
{ email: 'benjamin@bluemchen.de', value: '90' },
|
{ email: 'benjamin@bluemchen.de', value: '90' },
|
||||||
])
|
])
|
||||||
@ -162,7 +157,7 @@ describe('CreationFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Ouch!')
|
expect(toastErrorSpy).toBeCalledWith('Ouch!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -292,7 +287,7 @@ describe('CreationFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toast success message', () => {
|
it('toast success message', () => {
|
||||||
expect(toastedSuccessMock).toBeCalled()
|
expect(toastSuccessSpy).toBeCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('store commit openCreationPlus', () => {
|
it('store commit openCreationPlus', () => {
|
||||||
@ -426,13 +421,14 @@ describe('CreationFormular', () => {
|
|||||||
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 0)
|
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('toasts two errors', () => {
|
it('emits remove all bookmarks', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith(
|
expect(wrapper.emitted('remove-all-bookmark')).toBeTruthy()
|
||||||
'Could not created PendingCreation for bob@baumeister.de',
|
})
|
||||||
)
|
|
||||||
expect(toastedErrorMock).toBeCalledWith(
|
it('emits toast failed creations with two emails', () => {
|
||||||
'Could not created PendingCreation for bibi@bloxberg.de',
|
expect(wrapper.emitted('toast-failed-creations')).toEqual([
|
||||||
)
|
[['bob@baumeister.de', 'bibi@bloxberg.de']],
|
||||||
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -454,7 +450,7 @@ describe('CreationFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Oh no!')
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -166,20 +166,21 @@ export default {
|
|||||||
fetchPolicy: 'no-cache',
|
fetchPolicy: 'no-cache',
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
const failedCreations = []
|
||||||
this.$store.commit(
|
this.$store.commit(
|
||||||
'openCreationsPlus',
|
'openCreationsPlus',
|
||||||
result.data.createPendingCreations.successfulCreation.length,
|
result.data.createPendingCreations.successfulCreation.length,
|
||||||
)
|
)
|
||||||
if (result.data.createPendingCreations.failedCreation.length > 0) {
|
if (result.data.createPendingCreations.failedCreation.length > 0) {
|
||||||
result.data.createPendingCreations.failedCreation.forEach((failed) => {
|
result.data.createPendingCreations.failedCreation.forEach((email) => {
|
||||||
// TODO: Please localize this error message
|
failedCreations.push(email)
|
||||||
this.$toasted.error('Could not created PendingCreation for ' + failed)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.$emit('remove-all-bookmark')
|
this.$emit('remove-all-bookmark')
|
||||||
|
this.$emit('toast-failed-creations', failedCreations)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
} else if (this.type === 'singleCreation') {
|
} else if (this.type === 'singleCreation') {
|
||||||
submitObj = {
|
submitObj = {
|
||||||
@ -196,19 +197,19 @@ export default {
|
|||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$emit('update-user-data', this.item, result.data.createPendingCreation)
|
this.$emit('update-user-data', this.item, result.data.createPendingCreation)
|
||||||
this.$toasted.success(
|
this.$store.commit('openCreationsPlus', 1)
|
||||||
|
this.toastSuccess(
|
||||||
this.$t('creation_form.toasted', {
|
this.$t('creation_form.toasted', {
|
||||||
value: this.value,
|
value: this.value,
|
||||||
email: this.item.email,
|
email: this.item.email,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
this.$store.commit('openCreationsPlus', 1)
|
|
||||||
// what is this? Tests says that this.text is not reseted
|
// what is this? Tests says that this.text is not reseted
|
||||||
this.$refs.creationForm.reset()
|
this.$refs.creationForm.reset()
|
||||||
this.value = 0
|
this.value = 0
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
this.$refs.creationForm.reset()
|
this.$refs.creationForm.reset()
|
||||||
this.value = 0
|
this.value = 0
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import CreationTransactionListFormular from './CreationTransactionListFormular.vue'
|
import CreationTransactionListFormular from './CreationTransactionListFormular.vue'
|
||||||
|
import { toastErrorSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -50,17 +51,12 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const toastedErrorMock = jest.fn()
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$d: jest.fn((t) => t),
|
$d: jest.fn((t) => t),
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$apollo: {
|
$apollo: {
|
||||||
query: apolloQueryMock,
|
query: apolloQueryMock,
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: toastedErrorMock,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const propsData = {
|
const propsData = {
|
||||||
@ -109,7 +105,7 @@ describe('CreationTransactionListFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toast error', () => {
|
it('toast error', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('OUCH!')
|
expect(toastErrorSpy).toBeCalledWith('OUCH!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -63,7 +63,7 @@ export default {
|
|||||||
this.items = result.data.transactionList.transactions.filter((t) => t.type === 'creation')
|
this.items = result.data.transactionList.transactions.filter((t) => t.type === 'creation')
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils'
|
|||||||
import DeletedUserFormular from './DeletedUserFormular.vue'
|
import DeletedUserFormular from './DeletedUserFormular.vue'
|
||||||
import { deleteUser } from '../graphql/deleteUser'
|
import { deleteUser } from '../graphql/deleteUser'
|
||||||
import { unDeleteUser } from '../graphql/unDeleteUser'
|
import { unDeleteUser } from '../graphql/unDeleteUser'
|
||||||
|
import { toastErrorSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -13,9 +14,6 @@ const apolloMutateMock = jest.fn().mockResolvedValue({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const toastedErrorMock = jest.fn()
|
|
||||||
const toastedSuccessMock = jest.fn()
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$apollo: {
|
$apollo: {
|
||||||
@ -29,10 +27,6 @@ const mocks = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: toastedErrorMock,
|
|
||||||
success: toastedSuccessMock,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const propsData = {
|
const propsData = {
|
||||||
@ -118,10 +112,6 @@ describe('DeletedUserFormular', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
|
||||||
expect(toastedSuccessMock).toBeCalledWith('user_deleted')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('emits update deleted At', () => {
|
it('emits update deleted At', () => {
|
||||||
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
@ -147,7 +137,7 @@ describe('DeletedUserFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Oh no!')
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -215,10 +205,6 @@ describe('DeletedUserFormular', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
|
||||||
expect(toastedSuccessMock).toBeCalledWith('user_recovered')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('emits update deleted At', () => {
|
it('emits update deleted At', () => {
|
||||||
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
@ -244,7 +230,7 @@ describe('DeletedUserFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Oh no!')
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,6 @@ export default {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$toasted.success(this.$t('user_deleted'))
|
|
||||||
this.$emit('updateDeletedAt', {
|
this.$emit('updateDeletedAt', {
|
||||||
userId: this.item.userId,
|
userId: this.item.userId,
|
||||||
deletedAt: result.data.deleteUser,
|
deletedAt: result.data.deleteUser,
|
||||||
@ -53,7 +52,7 @@ export default {
|
|||||||
this.checked = false
|
this.checked = false
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
unDeleteUser() {
|
unDeleteUser() {
|
||||||
@ -65,7 +64,7 @@ export default {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$toasted.success(this.$t('user_recovered'))
|
this.toastSuccess(this.$t('user_recovered'))
|
||||||
this.$emit('updateDeletedAt', {
|
this.$emit('updateDeletedAt', {
|
||||||
userId: this.item.userId,
|
userId: this.item.userId,
|
||||||
deletedAt: result.data.unDeleteUser,
|
deletedAt: result.data.unDeleteUser,
|
||||||
@ -73,7 +72,7 @@ export default {
|
|||||||
this.checked = false
|
this.checked = false
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import EditCreationFormular from './EditCreationFormular.vue'
|
import EditCreationFormular from './EditCreationFormular.vue'
|
||||||
|
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -16,8 +17,6 @@ const apolloMutateMock = jest.fn().mockResolvedValue({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const stateCommitMock = jest.fn()
|
const stateCommitMock = jest.fn()
|
||||||
const toastedErrorMock = jest.fn()
|
|
||||||
const toastedSuccessMock = jest.fn()
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
@ -37,10 +36,6 @@ const mocks = {
|
|||||||
},
|
},
|
||||||
commit: stateCommitMock,
|
commit: stateCommitMock,
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: toastedErrorMock,
|
|
||||||
success: toastedSuccessMock,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = new Date(Date.now())
|
const now = new Date(Date.now())
|
||||||
@ -142,7 +137,7 @@ describe('EditCreationFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
it('toasts a success message', () => {
|
||||||
expect(toastedSuccessMock).toBeCalledWith('creation_form.toasted_update')
|
expect(toastSuccessSpy).toBeCalledWith('creation_form.toasted_update')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -155,7 +150,7 @@ describe('EditCreationFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Oh no!')
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -132,7 +132,7 @@ export default {
|
|||||||
moderator: Number(result.data.updatePendingCreation.moderator),
|
moderator: Number(result.data.updatePendingCreation.moderator),
|
||||||
row: this.row,
|
row: this.row,
|
||||||
})
|
})
|
||||||
this.$toasted.success(
|
this.toastSuccess(
|
||||||
this.$t('creation_form.toasted_update', {
|
this.$t('creation_form.toasted_update', {
|
||||||
value: this.value,
|
value: this.value,
|
||||||
email: this.item.email,
|
email: this.item.email,
|
||||||
@ -144,7 +144,7 @@ export default {
|
|||||||
this.value = 0
|
this.value = 0
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
// das creation Formular reseten
|
// das creation Formular reseten
|
||||||
this.$refs.updateCreationForm.reset()
|
this.$refs.updateCreationForm.reset()
|
||||||
// Den geschöpften Wert auf o setzen
|
// Den geschöpften Wert auf o setzen
|
||||||
|
|||||||
@ -73,10 +73,6 @@ const mocks = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: jest.fn(),
|
|
||||||
success: jest.fn(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('SearchUserTable', () => {
|
describe('SearchUserTable', () => {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
"confirmed": "bestätigt",
|
"confirmed": "bestätigt",
|
||||||
"creation": "Schöpfung",
|
"creation": "Schöpfung",
|
||||||
"creation_form": {
|
"creation_form": {
|
||||||
|
"creation_failed": "Ausstehende Schöpfung für {email} konnte nicht erzeugt werden.",
|
||||||
"creation_for": "Aktives Grundeinkommen für",
|
"creation_for": "Aktives Grundeinkommen für",
|
||||||
"enter_text": "Text eintragen",
|
"enter_text": "Text eintragen",
|
||||||
"form": "Schöpfungsformular",
|
"form": "Schöpfungsformular",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
"delete_user": "Nutzer löschen",
|
"delete_user": "Nutzer löschen",
|
||||||
"details": "Details",
|
"details": "Details",
|
||||||
"edit": "Bearbeiten",
|
"edit": "Bearbeiten",
|
||||||
|
"error": "Fehler",
|
||||||
"e_mail": "E-Mail",
|
"e_mail": "E-Mail",
|
||||||
"firstname": "Vorname",
|
"firstname": "Vorname",
|
||||||
"gradido_admin_footer": "Gradido Akademie Adminkonsole",
|
"gradido_admin_footer": "Gradido Akademie Adminkonsole",
|
||||||
@ -68,6 +70,7 @@
|
|||||||
"remove_all": "alle Nutzer entfernen",
|
"remove_all": "alle Nutzer entfernen",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
|
"success": "Erfolg",
|
||||||
"text": "Text",
|
"text": "Text",
|
||||||
"transaction": "Transaktion",
|
"transaction": "Transaktion",
|
||||||
"transactionlist": {
|
"transactionlist": {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
"confirmed": "confirmed",
|
"confirmed": "confirmed",
|
||||||
"creation": "Creation",
|
"creation": "Creation",
|
||||||
"creation_form": {
|
"creation_form": {
|
||||||
|
"creation_failed": "Could not create pending creation for {email}",
|
||||||
"creation_for": "Active Basic Income for",
|
"creation_for": "Active Basic Income for",
|
||||||
"enter_text": "Enter text",
|
"enter_text": "Enter text",
|
||||||
"form": "Creation form",
|
"form": "Creation form",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
"delete_user": "Delete user",
|
"delete_user": "Delete user",
|
||||||
"details": "Details",
|
"details": "Details",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
|
"error": "Error",
|
||||||
"e_mail": "E-mail",
|
"e_mail": "E-mail",
|
||||||
"firstname": "Firstname",
|
"firstname": "Firstname",
|
||||||
"gradido_admin_footer": "Gradido Academy Admin Console",
|
"gradido_admin_footer": "Gradido Academy Admin Console",
|
||||||
@ -68,6 +70,7 @@
|
|||||||
"remove_all": "Remove all users",
|
"remove_all": "Remove all users",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
|
"success": "Success",
|
||||||
"text": "Text",
|
"text": "Text",
|
||||||
"transaction": "Transaction",
|
"transaction": "Transaction",
|
||||||
"transactionlist": {
|
"transactionlist": {
|
||||||
|
|||||||
@ -13,31 +13,24 @@ import i18n from './i18n'
|
|||||||
|
|
||||||
import VueApollo from 'vue-apollo'
|
import VueApollo from 'vue-apollo'
|
||||||
|
|
||||||
|
import PortalVue from 'portal-vue'
|
||||||
|
|
||||||
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
|
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
|
||||||
import 'bootstrap/dist/css/bootstrap.css'
|
import 'bootstrap/dist/css/bootstrap.css'
|
||||||
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||||
|
|
||||||
import Toasted from 'vue-toasted'
|
import { toasters } from './mixins/toaster'
|
||||||
|
|
||||||
import { apolloProvider } from './plugins/apolloProvider'
|
import { apolloProvider } from './plugins/apolloProvider'
|
||||||
|
|
||||||
|
Vue.use(PortalVue)
|
||||||
Vue.use(BootstrapVue)
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
Vue.use(IconsPlugin)
|
Vue.use(IconsPlugin)
|
||||||
|
|
||||||
Vue.use(VueApollo)
|
Vue.use(VueApollo)
|
||||||
|
|
||||||
Vue.use(Toasted, {
|
Vue.mixin(toasters)
|
||||||
position: 'top-center',
|
|
||||||
duration: 5000,
|
|
||||||
fullWidth: true,
|
|
||||||
action: {
|
|
||||||
text: 'x',
|
|
||||||
onClick: (e, toastObject) => {
|
|
||||||
toastObject.goAway(0)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
addNavigationGuards(router, store, apolloProvider.defaultClient, i18n)
|
addNavigationGuards(router, store, apolloProvider.defaultClient, i18n)
|
||||||
|
|
||||||
|
|||||||
30
admin/src/mixins/toaster.js
Normal file
30
admin/src/mixins/toaster.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export const toasters = {
|
||||||
|
methods: {
|
||||||
|
toastSuccess(message) {
|
||||||
|
this.toast(message, {
|
||||||
|
title: this.$t('success'),
|
||||||
|
variant: 'success',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toastError(message) {
|
||||||
|
this.toast(message, {
|
||||||
|
title: this.$t('error'),
|
||||||
|
variant: 'danger',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toast(message, options) {
|
||||||
|
// for unit tests, check that replace is present
|
||||||
|
if (message.replace) message = message.replace(/^GraphQL error: /, '')
|
||||||
|
this.$bvToast.toast(message, {
|
||||||
|
autoHideDelay: 5000,
|
||||||
|
appendToast: true,
|
||||||
|
solid: true,
|
||||||
|
toaster: 'b-toaster-top-right',
|
||||||
|
headerClass: 'gdd-toaster-title',
|
||||||
|
bodyClass: 'gdd-toaster-body',
|
||||||
|
toastClass: 'gdd-toaster',
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import Creation from './Creation.vue'
|
import Creation from './Creation.vue'
|
||||||
|
import { toastErrorSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -29,18 +30,14 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const toastErrorMock = jest.fn()
|
|
||||||
const storeCommitMock = jest.fn()
|
const storeCommitMock = jest.fn()
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t, options) => (options ? [t, options] : t)),
|
||||||
$d: jest.fn((d) => d),
|
$d: jest.fn((d) => d),
|
||||||
$apollo: {
|
$apollo: {
|
||||||
query: apolloQueryMock,
|
query: apolloQueryMock,
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: toastErrorMock,
|
|
||||||
},
|
|
||||||
$store: {
|
$store: {
|
||||||
commit: storeCommitMock,
|
commit: storeCommitMock,
|
||||||
state: {
|
state: {
|
||||||
@ -236,6 +233,25 @@ describe('Creation', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('failed creations', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await wrapper
|
||||||
|
.findComponent({ name: 'CreationFormular' })
|
||||||
|
.vm.$emit('toast-failed-creations', ['bibi@bloxberg.de', 'benjamin@bluemchen.de'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts two error messages', () => {
|
||||||
|
expect(toastErrorSpy).toBeCalledWith([
|
||||||
|
'creation_form.creation_failed',
|
||||||
|
{ email: 'bibi@bloxberg.de' },
|
||||||
|
])
|
||||||
|
expect(toastErrorSpy).toBeCalledWith([
|
||||||
|
'creation_form.creation_failed',
|
||||||
|
{ email: 'benjamin@bluemchen.de' },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('watchers', () => {
|
describe('watchers', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
@ -298,7 +314,7 @@ describe('Creation', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastErrorMock).toBeCalledWith('Ouch')
|
expect(toastErrorSpy).toBeCalledWith('Ouch')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
:creation="creation"
|
:creation="creation"
|
||||||
:items="itemsMassCreation"
|
:items="itemsMassCreation"
|
||||||
@remove-all-bookmark="removeAllBookmarks"
|
@remove-all-bookmark="removeAllBookmarks"
|
||||||
|
@toast-failed-creations="toastFailedCreations"
|
||||||
/>
|
/>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
@ -118,7 +119,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
pushItem(selectedItem) {
|
pushItem(selectedItem) {
|
||||||
@ -144,6 +145,11 @@ export default {
|
|||||||
this.$store.commit('setUserSelectedInMassCreation', [])
|
this.$store.commit('setUserSelectedInMassCreation', [])
|
||||||
this.getUsers()
|
this.getUsers()
|
||||||
},
|
},
|
||||||
|
toastFailedCreations(failedCreations) {
|
||||||
|
failedCreations.forEach((email) =>
|
||||||
|
this.toastError(this.$t('creation_form.creation_failed', { email })),
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
Searchfields() {
|
Searchfields() {
|
||||||
|
|||||||
@ -2,12 +2,11 @@ import { mount } from '@vue/test-utils'
|
|||||||
import CreationConfirm from './CreationConfirm.vue'
|
import CreationConfirm from './CreationConfirm.vue'
|
||||||
import { deletePendingCreation } from '../graphql/deletePendingCreation'
|
import { deletePendingCreation } from '../graphql/deletePendingCreation'
|
||||||
import { confirmPendingCreation } from '../graphql/confirmPendingCreation'
|
import { confirmPendingCreation } from '../graphql/confirmPendingCreation'
|
||||||
|
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
const storeCommitMock = jest.fn()
|
const storeCommitMock = jest.fn()
|
||||||
const toastedErrorMock = jest.fn()
|
|
||||||
const toastedSuccessMock = jest.fn()
|
|
||||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
getPendingCreations: [
|
getPendingCreations: [
|
||||||
@ -47,10 +46,6 @@ const mocks = {
|
|||||||
query: apolloQueryMock,
|
query: apolloQueryMock,
|
||||||
mutate: apolloMutateMock,
|
mutate: apolloMutateMock,
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: toastedErrorMock,
|
|
||||||
success: toastedSuccessMock,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('CreationConfirm', () => {
|
describe('CreationConfirm', () => {
|
||||||
@ -101,7 +96,7 @@ describe('CreationConfirm', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
it('toasts a success message', () => {
|
||||||
expect(toastedSuccessMock).toBeCalledWith('creation_form.toasted_delete')
|
expect(toastSuccessSpy).toBeCalledWith('creation_form.toasted_delete')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -112,7 +107,7 @@ describe('CreationConfirm', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Ouchhh!')
|
expect(toastErrorSpy).toBeCalledWith('Ouchhh!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -158,7 +153,7 @@ describe('CreationConfirm', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
it('toasts a success message', () => {
|
||||||
expect(toastedSuccessMock).toBeCalledWith('creation_form.toasted_created')
|
expect(toastSuccessSpy).toBeCalledWith('creation_form.toasted_created')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has 1 item left in the table', () => {
|
it('has 1 item left in the table', () => {
|
||||||
@ -173,7 +168,7 @@ describe('CreationConfirm', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Ouchhh!')
|
expect(toastErrorSpy).toBeCalledWith('Ouchhh!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -189,7 +184,7 @@ describe('CreationConfirm', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toast an error message', () => {
|
it('toast an error message', () => {
|
||||||
expect(toastedErrorMock).toBeCalledWith('Ouch!')
|
expect(toastErrorSpy).toBeCalledWith('Ouch!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -43,10 +43,10 @@ export default {
|
|||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.updatePendingCreations(item.id)
|
this.updatePendingCreations(item.id)
|
||||||
this.$toasted.success(this.$t('creation_form.toasted_delete'))
|
this.toastSuccess(this.$t('creation_form.toasted_delete'))
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
confirmCreation() {
|
confirmCreation() {
|
||||||
@ -60,11 +60,11 @@ export default {
|
|||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.overlay = false
|
this.overlay = false
|
||||||
this.updatePendingCreations(this.item.id)
|
this.updatePendingCreations(this.item.id)
|
||||||
this.$toasted.success(this.$t('creation_form.toasted_created'))
|
this.toastSuccess(this.$t('creation_form.toasted_created'))
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.overlay = false
|
this.overlay = false
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getPendingCreations() {
|
getPendingCreations() {
|
||||||
@ -79,7 +79,7 @@ export default {
|
|||||||
this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
|
this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updatePendingCreations(id) {
|
updatePendingCreations(id) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import UserSearch from './UserSearch.vue'
|
import UserSearch from './UserSearch.vue'
|
||||||
|
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
|||||||
email: 'bibi@bloxberg.de',
|
email: 'bibi@bloxberg.de',
|
||||||
creation: [200, 400, 600],
|
creation: [200, 400, 600],
|
||||||
emailChecked: true,
|
emailChecked: true,
|
||||||
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
userId: 2,
|
userId: 2,
|
||||||
@ -23,6 +25,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
|||||||
email: 'benjamin@bluemchen.de',
|
email: 'benjamin@bluemchen.de',
|
||||||
creation: [1000, 1000, 1000],
|
creation: [1000, 1000, 1000],
|
||||||
emailChecked: true,
|
emailChecked: true,
|
||||||
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
userId: 3,
|
userId: 3,
|
||||||
@ -31,6 +34,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
|||||||
email: 'peter@lustig.de',
|
email: 'peter@lustig.de',
|
||||||
creation: [0, 0, 0],
|
creation: [0, 0, 0],
|
||||||
emailChecked: true,
|
emailChecked: true,
|
||||||
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
userId: 4,
|
userId: 4,
|
||||||
@ -39,23 +43,19 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
|||||||
email: 'new@user.ch',
|
email: 'new@user.ch',
|
||||||
creation: [1000, 1000, 1000],
|
creation: [1000, 1000, 1000],
|
||||||
emailChecked: false,
|
emailChecked: false,
|
||||||
|
deletedAt: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const toastErrorMock = jest.fn()
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$d: jest.fn((d) => String(d)),
|
$d: jest.fn((d) => String(d)),
|
||||||
$apollo: {
|
$apollo: {
|
||||||
query: apolloQueryMock,
|
query: apolloQueryMock,
|
||||||
},
|
},
|
||||||
$toasted: {
|
|
||||||
error: toastErrorMock,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('UserSearch', () => {
|
describe('UserSearch', () => {
|
||||||
@ -187,6 +187,21 @@ describe('UserSearch', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('delete user', () => {
|
||||||
|
const now = new Date()
|
||||||
|
beforeEach(async () => {
|
||||||
|
wrapper.findComponent({ name: 'SearchUserTable' }).vm.$emit('updateDeletedAt', 4, now)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('marks the user as deleted', () => {
|
||||||
|
expect(wrapper.vm.searchResult.find((obj) => obj.userId === 4).deletedAt).toEqual(now)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts a success message', () => {
|
||||||
|
expect(toastSuccessSpy).toBeCalledWith('user_deleted')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('apollo returns error', () => {
|
describe('apollo returns error', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
apolloQueryMock.mockRejectedValue({
|
apolloQueryMock.mockRejectedValue({
|
||||||
@ -196,7 +211,7 @@ describe('UserSearch', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
expect(toastErrorMock).toBeCalledWith('Ouch')
|
expect(toastErrorSpy).toBeCalledWith('Ouch')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -94,11 +94,12 @@ export default {
|
|||||||
this.searchResult = result.data.searchUsers.userList
|
this.searchResult = result.data.searchUsers.userList
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateDeletedAt(userId, deletedAt) {
|
updateDeletedAt(userId, deletedAt) {
|
||||||
this.searchResult.find((obj) => obj.userId === userId).deletedAt = deletedAt
|
this.searchResult.find((obj) => obj.userId === userId).deletedAt = deletedAt
|
||||||
|
this.toastSuccess(this.$t('user_deleted'))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
@ -5,11 +5,18 @@ import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
|
|||||||
// without this async calls are not working
|
// without this async calls are not working
|
||||||
import 'regenerator-runtime'
|
import 'regenerator-runtime'
|
||||||
|
|
||||||
|
import { toasters } from '../src/mixins/toaster'
|
||||||
|
|
||||||
|
export const toastErrorSpy = jest.spyOn(toasters.methods, 'toastError')
|
||||||
|
export const toastSuccessSpy = jest.spyOn(toasters.methods, 'toastSuccess')
|
||||||
|
|
||||||
global.localVue = createLocalVue()
|
global.localVue = createLocalVue()
|
||||||
|
|
||||||
global.localVue.use(BootstrapVue)
|
global.localVue.use(BootstrapVue)
|
||||||
global.localVue.use(IconsPlugin)
|
global.localVue.use(IconsPlugin)
|
||||||
|
|
||||||
|
global.localVue.mixin(toasters)
|
||||||
|
|
||||||
// throw errors for vue warnings to force the programmers to take care about warnings
|
// throw errors for vue warnings to force the programmers to take care about warnings
|
||||||
Vue.config.warnHandler = (w) => {
|
Vue.config.warnHandler = (w) => {
|
||||||
throw new Error(w)
|
throw new Error(w)
|
||||||
|
|||||||
@ -12512,11 +12512,6 @@ 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"
|
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
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==
|
|
||||||
|
|
||||||
vue@^2.6.11:
|
vue@^2.6.11:
|
||||||
version "2.6.14"
|
version "2.6.14"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||||
|
|||||||
@ -17,6 +17,6 @@ export class Balance {
|
|||||||
@Field(() => Decimal)
|
@Field(() => Decimal)
|
||||||
decay: Decimal
|
decay: Decimal
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => Date)
|
||||||
decayDate: string
|
decayDate: Date
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
import { ObjectType, Field, Int } from 'type-graphql'
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { ObjectType, Field } from 'type-graphql'
|
|
||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
@ -31,6 +29,6 @@ export class Decay {
|
|||||||
@Field(() => Date, { nullable: true })
|
@Field(() => Date, { nullable: true })
|
||||||
end: Date | null
|
end: Date | null
|
||||||
|
|
||||||
@Field(() => Number, { nullable: true })
|
@Field(() => Int, { nullable: true })
|
||||||
duration: number | null
|
duration: number | null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { ObjectType, Field } from 'type-graphql'
|
import { ObjectType, Field } from 'type-graphql'
|
||||||
import { Decay } from './Decay'
|
import { Decay } from './Decay'
|
||||||
import { Transaction as dbTransaction } from '@entity/Transaction'
|
import { Transaction as dbTransaction } from '@entity/Transaction'
|
||||||
@ -25,7 +23,7 @@ export class Transaction {
|
|||||||
transaction.decay,
|
transaction.decay,
|
||||||
transaction.decayStart,
|
transaction.decayStart,
|
||||||
transaction.balanceDate,
|
transaction.balanceDate,
|
||||||
(transaction.balanceDate.getTime() - transaction.decayStart.getTime()) / 1000,
|
Math.round((transaction.balanceDate.getTime() - transaction.decayStart.getTime()) / 1000),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
this.memo = transaction.memo
|
this.memo = transaction.memo
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { ObjectType, Field } from 'type-graphql'
|
import { ObjectType, Field } from 'type-graphql'
|
||||||
import CONFIG from '../../config'
|
import CONFIG from '../../config'
|
||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { ObjectType, Field } from 'type-graphql'
|
import { ObjectType, Field } from 'type-graphql'
|
||||||
import { KlickTipp } from './KlickTipp'
|
import { KlickTipp } from './KlickTipp'
|
||||||
import { User as dbUser } from '@entity/User'
|
import { User as dbUser } from '@entity/User'
|
||||||
|
|||||||
@ -307,13 +307,13 @@ export class AdminResolver {
|
|||||||
const receivedCallDate = new Date()
|
const receivedCallDate = new Date()
|
||||||
|
|
||||||
const transactionRepository = getCustomRepository(TransactionRepository)
|
const transactionRepository = getCustomRepository(TransactionRepository)
|
||||||
const lastUserTransaction = await transactionRepository.findLastForUser(pendingCreation.userId)
|
const lastTransaction = await transactionRepository.findLastForUser(pendingCreation.userId)
|
||||||
|
|
||||||
let newBalance = new Decimal(0)
|
let newBalance = new Decimal(0)
|
||||||
if (lastUserTransaction) {
|
if (lastTransaction) {
|
||||||
newBalance = calculateDecay(
|
newBalance = calculateDecay(
|
||||||
lastUserTransaction.balance,
|
lastTransaction.balance,
|
||||||
lastUserTransaction.balanceDate,
|
lastTransaction.balanceDate,
|
||||||
receivedCallDate,
|
receivedCallDate,
|
||||||
).balance
|
).balance
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,8 @@ import { RIGHTS } from '../../auth/RIGHTS'
|
|||||||
import { User } from '../model/User'
|
import { User } from '../model/User'
|
||||||
import { communityUser } from '../../util/communityUser'
|
import { communityUser } from '../../util/communityUser'
|
||||||
import { virtualDecayTransaction } from '../../util/virtualDecayTransaction'
|
import { virtualDecayTransaction } from '../../util/virtualDecayTransaction'
|
||||||
import Decimal from '../scalar/Decimal'
|
import Decimal from 'decimal.js-light'
|
||||||
|
import { calculateDecay } from '../../util/decay'
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
export class TransactionResolver {
|
export class TransactionResolver {
|
||||||
@ -47,6 +48,7 @@ export class TransactionResolver {
|
|||||||
}: Paginated,
|
}: Paginated,
|
||||||
@Ctx() context: any,
|
@Ctx() context: any,
|
||||||
): Promise<TransactionList> {
|
): Promise<TransactionList> {
|
||||||
|
const now = new Date()
|
||||||
// find user
|
// find user
|
||||||
const userRepository = getCustomRepository(UserRepository)
|
const userRepository = getCustomRepository(UserRepository)
|
||||||
// TODO: separate those usecases - this is a security issue
|
// TODO: separate those usecases - this is a security issue
|
||||||
@ -60,65 +62,6 @@ export class TransactionResolver {
|
|||||||
{ order: { balanceDate: 'DESC' } },
|
{ order: { balanceDate: 'DESC' } },
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!lastTransaction) {
|
|
||||||
// TODO Have proper return type here
|
|
||||||
throw new Error('User has no transactions')
|
|
||||||
}
|
|
||||||
|
|
||||||
// find transactions
|
|
||||||
const limit = currentPage === 1 && order === Order.DESC ? pageSize - 1 : pageSize
|
|
||||||
const offset =
|
|
||||||
currentPage === 1 ? 0 : (currentPage - 1) * pageSize - (order === Order.DESC ? 1 : 0)
|
|
||||||
const transactionRepository = getCustomRepository(TransactionRepository)
|
|
||||||
const [userTransactions, userTransactionsCount] = await transactionRepository.findByUserPaged(
|
|
||||||
user.id,
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
order,
|
|
||||||
onlyCreations,
|
|
||||||
)
|
|
||||||
|
|
||||||
// find involved users
|
|
||||||
let involvedUserIds: number[] = []
|
|
||||||
userTransactions.forEach((transaction: dbTransaction) => {
|
|
||||||
involvedUserIds.push(transaction.userId)
|
|
||||||
if (transaction.linkedUserId) {
|
|
||||||
involvedUserIds.push(transaction.linkedUserId)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// remove duplicates
|
|
||||||
involvedUserIds = involvedUserIds.filter((value, index, self) => self.indexOf(value) === index)
|
|
||||||
// We need to show the name for deleted users for old transactions
|
|
||||||
const involvedDbUsers = await dbUser
|
|
||||||
.createQueryBuilder()
|
|
||||||
.withDeleted()
|
|
||||||
.where('id IN (:...userIds)', { userIds: involvedUserIds })
|
|
||||||
.getMany()
|
|
||||||
const involvedUsers = involvedDbUsers.map((u) => new User(u))
|
|
||||||
|
|
||||||
const self = new User(user)
|
|
||||||
const transactions: Transaction[] = []
|
|
||||||
|
|
||||||
// decay transaction
|
|
||||||
if (currentPage === 1 && order === Order.DESC) {
|
|
||||||
const now = new Date()
|
|
||||||
transactions.push(
|
|
||||||
virtualDecayTransaction(lastTransaction.balance, lastTransaction.balanceDate, now, self),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// transactions
|
|
||||||
for (let i = 0; i < userTransactions.length; i++) {
|
|
||||||
const userTransaction = userTransactions[i]
|
|
||||||
let linkedUser = null
|
|
||||||
if (userTransaction.typeId === TypeId.CREATION) {
|
|
||||||
linkedUser = communityUser
|
|
||||||
} else {
|
|
||||||
linkedUser = involvedUsers.find((u) => u.id === userTransaction.linkedUserId)
|
|
||||||
}
|
|
||||||
transactions.push(new Transaction(userTransaction, self, linkedUser))
|
|
||||||
}
|
|
||||||
|
|
||||||
// get GDT
|
// get GDT
|
||||||
let balanceGDT = null
|
let balanceGDT = null
|
||||||
try {
|
try {
|
||||||
@ -134,9 +77,59 @@ export class TransactionResolver {
|
|||||||
console.log('Could not query GDT Server', err)
|
console.log('Could not query GDT Server', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!lastTransaction) {
|
||||||
|
return new TransactionList(new Decimal(0), [], 0, balanceGDT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// find transactions
|
||||||
|
// first page can contain 26 due to virtual decay transaction
|
||||||
|
const offset = (currentPage - 1) * pageSize
|
||||||
|
const transactionRepository = getCustomRepository(TransactionRepository)
|
||||||
|
const [userTransactions, userTransactionsCount] = await transactionRepository.findByUserPaged(
|
||||||
|
user.id,
|
||||||
|
pageSize,
|
||||||
|
offset,
|
||||||
|
order,
|
||||||
|
onlyCreations,
|
||||||
|
)
|
||||||
|
|
||||||
|
// find involved users; I am involved
|
||||||
|
const involvedUserIds: number[] = [user.id]
|
||||||
|
userTransactions.forEach((transaction: dbTransaction) => {
|
||||||
|
if (transaction.linkedUserId && !involvedUserIds.includes(transaction.linkedUserId)) {
|
||||||
|
involvedUserIds.push(transaction.linkedUserId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// We need to show the name for deleted users for old transactions
|
||||||
|
const involvedDbUsers = await dbUser
|
||||||
|
.createQueryBuilder()
|
||||||
|
.withDeleted()
|
||||||
|
.where('id IN (:...userIds)', { userIds: involvedUserIds })
|
||||||
|
.getMany()
|
||||||
|
const involvedUsers = involvedDbUsers.map((u) => new User(u))
|
||||||
|
|
||||||
|
const self = new User(user)
|
||||||
|
const transactions: Transaction[] = []
|
||||||
|
|
||||||
|
// decay transaction
|
||||||
|
if (currentPage === 1 && order === Order.DESC) {
|
||||||
|
transactions.push(
|
||||||
|
virtualDecayTransaction(lastTransaction.balance, lastTransaction.balanceDate, now, self),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// transactions
|
||||||
|
userTransactions.forEach((userTransaction) => {
|
||||||
|
const linkedUser =
|
||||||
|
userTransaction.typeId === TransactionTypeId.CREATION
|
||||||
|
? communityUser
|
||||||
|
: involvedUsers.find((u) => u.id === userTransaction.linkedUserId)
|
||||||
|
transactions.push(new Transaction(userTransaction, self, linkedUser))
|
||||||
|
})
|
||||||
|
|
||||||
// Construct Result
|
// Construct Result
|
||||||
return new TransactionList(
|
return new TransactionList(
|
||||||
lastTransaction.balance,
|
calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now).balance,
|
||||||
transactions,
|
transactions,
|
||||||
userTransactionsCount,
|
userTransactionsCount,
|
||||||
balanceGDT,
|
balanceGDT,
|
||||||
@ -184,7 +177,7 @@ export class TransactionResolver {
|
|||||||
transactionSend.memo = memo
|
transactionSend.memo = memo
|
||||||
transactionSend.userId = senderUser.id
|
transactionSend.userId = senderUser.id
|
||||||
transactionSend.linkedUserId = recipientUser.id
|
transactionSend.linkedUserId = recipientUser.id
|
||||||
transactionSend.amount = amount
|
transactionSend.amount = amount.mul(-1)
|
||||||
transactionSend.balance = sendBalance.balance
|
transactionSend.balance = sendBalance.balance
|
||||||
transactionSend.balanceDate = receivedCallDate
|
transactionSend.balanceDate = receivedCallDate
|
||||||
transactionSend.decay = sendBalance.decay.decay
|
transactionSend.decay = sendBalance.decay.decay
|
||||||
|
|||||||
@ -7,36 +7,35 @@ describe('utils/decay', () => {
|
|||||||
it('has base 0.99999997802044727', () => {
|
it('has base 0.99999997802044727', () => {
|
||||||
const amount = new Decimal(1.0)
|
const amount = new Decimal(1.0)
|
||||||
const seconds = 1
|
const seconds = 1
|
||||||
expect(decayFormula(amount, seconds)).toBe(0.99999997802044727)
|
// TODO: toString() was required, we could not compare two decimals
|
||||||
})
|
expect(decayFormula(amount, seconds).toString()).toBe('0.999999978035040489732012')
|
||||||
// Not sure if the following skiped tests make sence!?
|
|
||||||
it('has negative decay?', async () => {
|
|
||||||
const amount = new Decimal(1.0)
|
|
||||||
const seconds = 1
|
|
||||||
expect(decayFormula(amount, seconds)).toBe(-0.99999997802044727)
|
|
||||||
})
|
})
|
||||||
it('has correct backward calculation', async () => {
|
it('has correct backward calculation', async () => {
|
||||||
const amount = new Decimal(1.0)
|
const amount = new Decimal(1.0)
|
||||||
const seconds = -1
|
const seconds = -1
|
||||||
expect(decayFormula(amount, seconds)).toBe(1.0000000219795533)
|
expect(decayFormula(amount, seconds).toString()).toBe('1.000000021964959992727444')
|
||||||
})
|
})
|
||||||
// not possible, nodejs hasn't enough accuracy
|
// we get pretty close, but not exact here, skipping
|
||||||
it('has correct forward calculation', async () => {
|
it.skip('has correct forward calculation', async () => {
|
||||||
const amount = new Decimal(1.0).div(0.99999997802044727)
|
const amount = new Decimal(1.0).div(
|
||||||
|
new Decimal('0.99999997803504048973201202316767079413460520837376'),
|
||||||
|
)
|
||||||
const seconds = 1
|
const seconds = 1
|
||||||
expect(decayFormula(amount, seconds)).toBe(1.0)
|
expect(decayFormula(amount, seconds).toString()).toBe('1.0')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
it.skip('has base 0.99999997802044727', async () => {
|
it('has base 0.99999997802044727', async () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
now.setSeconds(1)
|
now.setSeconds(1)
|
||||||
const oneSecondAgo = new Date(now.getTime())
|
const oneSecondAgo = new Date(now.getTime())
|
||||||
oneSecondAgo.setSeconds(0)
|
oneSecondAgo.setSeconds(0)
|
||||||
expect(calculateDecay(new Decimal(1.0), oneSecondAgo, now)).toBe(0.99999997802044727)
|
expect(calculateDecay(new Decimal(1.0), oneSecondAgo, now).balance.toString()).toBe(
|
||||||
|
'0.999999978035040489732012',
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns input amount when from and to is the same', async () => {
|
it('returns input amount when from and to is the same', async () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
expect(calculateDecay(new Decimal(100.0), now, now).balance).toBe(100.0)
|
expect(calculateDecay(new Decimal(100.0), now, now).balance.toString()).toBe('100')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import Faker from 'faker'
|
|||||||
import { define } from 'typeorm-seeding'
|
import { define } from 'typeorm-seeding'
|
||||||
import { Transaction } from '../../entity/Transaction'
|
import { Transaction } from '../../entity/Transaction'
|
||||||
import { TransactionContext } from '../interface/TransactionContext'
|
import { TransactionContext } from '../interface/TransactionContext'
|
||||||
|
import Decimal from 'decimal.js-light'
|
||||||
|
|
||||||
define(Transaction, (faker: typeof Faker, context?: TransactionContext) => {
|
define(Transaction, (faker: typeof Faker, context?: TransactionContext) => {
|
||||||
if (!context) {
|
if (!context) {
|
||||||
@ -12,6 +13,8 @@ define(Transaction, (faker: typeof Faker, context?: TransactionContext) => {
|
|||||||
transaction.typeId = context.typeId // || 2
|
transaction.typeId = context.typeId // || 2
|
||||||
transaction.userId = context.userId
|
transaction.userId = context.userId
|
||||||
transaction.amount = context.amount
|
transaction.amount = context.amount
|
||||||
|
transaction.balance = context.balance
|
||||||
|
transaction.decay = new Decimal(0) // context.decay
|
||||||
transaction.memo = context.memo
|
transaction.memo = context.memo
|
||||||
transaction.creationDate = context.creationDate || new Date()
|
transaction.creationDate = context.creationDate || new Date()
|
||||||
// transaction.sendReceiverPublicKey = context.sendReceiverPublicKey || null
|
// transaction.sendReceiverPublicKey = context.sendReceiverPublicKey || null
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user