Merge branch 'master' of github.com:gradido/gradido into disable-change-month-for-contribution-updates

This commit is contained in:
Wolfgang Huß 2022-10-13 10:10:03 +02:00
commit 98e64ed867
21 changed files with 335 additions and 255 deletions

View File

@ -3,11 +3,15 @@ import NavBar from './NavBar.vue'
const localVue = global.localVue const localVue = global.localVue
const apolloMutateMock = jest.fn()
const storeDispatchMock = jest.fn() const storeDispatchMock = jest.fn()
const routerPushMock = jest.fn() const routerPushMock = jest.fn()
const mocks = { const mocks = {
$t: jest.fn((t) => t), $t: jest.fn((t) => t),
$apollo: {
mutate: apolloMutateMock,
},
$store: { $store: {
state: { state: {
openCreations: 1, openCreations: 1,
@ -69,5 +73,9 @@ describe('NavBar', () => {
it('dispatches logout to store', () => { it('dispatches logout to store', () => {
expect(storeDispatchMock).toBeCalledWith('logout') expect(storeDispatchMock).toBeCalledWith('logout')
}) })
it('has called logout mutation', () => {
expect(apolloMutateMock).toBeCalled()
})
}) })
}) })

View File

@ -28,14 +28,18 @@
</template> </template>
<script> <script>
import CONFIG from '../config' import CONFIG from '../config'
import { logout } from '../graphql/logout'
export default { export default {
name: 'navbar', name: 'navbar',
methods: { methods: {
logout() { async logout() {
window.location.assign(CONFIG.WALLET_URL) window.location.assign(CONFIG.WALLET_URL)
// window.location = CONFIG.WALLET_URL // window.location = CONFIG.WALLET_URL
this.$store.dispatch('logout') this.$store.dispatch('logout')
await this.$apollo.mutate({
mutation: logout,
})
}, },
wallet() { wallet() {
window.location = CONFIG.WALLET_AUTH_URL.replace('{token}', this.$store.state.token) window.location = CONFIG.WALLET_AUTH_URL.replace('{token}', this.$store.state.token)

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const logout = gql`
mutation {
logout
}
`

View File

@ -13,6 +13,7 @@ import { peterLustig } from '@/seeds/users/peter-lustig'
import { stephenHawking } from '@/seeds/users/stephen-hawking' import { stephenHawking } from '@/seeds/users/stephen-hawking'
import { garrickOllivander } from '@/seeds/users/garrick-ollivander' import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
import { import {
login,
setUserRole, setUserRole,
deleteUser, deleteUser,
unDeleteUser, unDeleteUser,
@ -27,7 +28,6 @@ import {
} from '@/seeds/graphql/mutations' } from '@/seeds/graphql/mutations'
import { import {
listUnconfirmedContributions, listUnconfirmedContributions,
login,
searchUsers, searchUsers,
listTransactionLinksAdmin, listTransactionLinksAdmin,
listContributionLinks, listContributionLinks,
@ -96,8 +96,8 @@ describe('AdminResolver', () => {
describe('without admin rights', () => { describe('without admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -121,8 +121,8 @@ describe('AdminResolver', () => {
describe('with admin rights', () => { describe('with admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
admin = await userFactory(testEnv, peterLustig) admin = await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })
@ -249,8 +249,8 @@ describe('AdminResolver', () => {
describe('without admin rights', () => { describe('without admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -274,8 +274,8 @@ describe('AdminResolver', () => {
describe('with admin rights', () => { describe('with admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
admin = await userFactory(testEnv, peterLustig) admin = await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })
@ -357,8 +357,8 @@ describe('AdminResolver', () => {
describe('without admin rights', () => { describe('without admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -382,8 +382,8 @@ describe('AdminResolver', () => {
describe('with admin rights', () => { describe('with admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
admin = await userFactory(testEnv, peterLustig) admin = await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })
@ -469,8 +469,8 @@ describe('AdminResolver', () => {
describe('without admin rights', () => { describe('without admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -514,8 +514,8 @@ describe('AdminResolver', () => {
beforeAll(async () => { beforeAll(async () => {
admin = await userFactory(testEnv, peterLustig) admin = await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
@ -766,8 +766,8 @@ describe('AdminResolver', () => {
describe('without admin rights', () => { describe('without admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -875,8 +875,8 @@ describe('AdminResolver', () => {
describe('with admin rights', () => { describe('with admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
admin = await userFactory(testEnv, peterLustig) admin = await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })
@ -1559,8 +1559,8 @@ describe('AdminResolver', () => {
describe('without admin rights', () => { describe('without admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -1605,8 +1605,8 @@ describe('AdminResolver', () => {
} }
// admin: only now log in // admin: only now log in
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })
@ -1865,8 +1865,8 @@ describe('AdminResolver', () => {
describe('without admin rights', () => { describe('without admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -1939,8 +1939,8 @@ describe('AdminResolver', () => {
describe('with admin rights', () => { describe('with admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, peterLustig) user = await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })

View File

@ -7,8 +7,9 @@ import {
adminCreateContributionMessage, adminCreateContributionMessage,
createContribution, createContribution,
createContributionMessage, createContributionMessage,
login,
} from '@/seeds/graphql/mutations' } from '@/seeds/graphql/mutations'
import { listContributionMessages, login } from '@/seeds/graphql/queries' import { listContributionMessages } from '@/seeds/graphql/queries'
import { userFactory } from '@/seeds/factory/user' import { userFactory } from '@/seeds/factory/user'
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
import { peterLustig } from '@/seeds/users/peter-lustig' import { peterLustig } from '@/seeds/users/peter-lustig'
@ -21,14 +22,13 @@ jest.mock('@/mailer/sendAddedContributionMessageEmail', () => {
} }
}) })
let mutate: any, query: any, con: any let mutate: any, con: any
let testEnv: any let testEnv: any
let result: any let result: any
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query
con = testEnv.con con = testEnv.con
await cleanDB() await cleanDB()
}) })
@ -59,8 +59,8 @@ describe('ContributionMessageResolver', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
await userFactory(testEnv, peterLustig) await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
result = await mutate({ result = await mutate({
@ -71,8 +71,8 @@ describe('ContributionMessageResolver', () => {
creationDate: new Date().toString(), creationDate: new Date().toString(),
}, },
}) })
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })
@ -103,8 +103,8 @@ describe('ContributionMessageResolver', () => {
}) })
it('throws error when contribution.userId equals user.id', async () => { it('throws error when contribution.userId equals user.id', async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
const result2 = await mutate({ const result2 = await mutate({
@ -195,8 +195,8 @@ describe('ContributionMessageResolver', () => {
describe('authenticated', () => { describe('authenticated', () => {
beforeAll(async () => { beforeAll(async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -227,8 +227,8 @@ describe('ContributionMessageResolver', () => {
}) })
it('throws error when other user tries to send createContributionMessage', async () => { it('throws error when other user tries to send createContributionMessage', async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
await expect( await expect(
@ -253,8 +253,8 @@ describe('ContributionMessageResolver', () => {
describe('valid input', () => { describe('valid input', () => {
beforeAll(async () => { beforeAll(async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -304,8 +304,8 @@ describe('ContributionMessageResolver', () => {
describe('authenticated', () => { describe('authenticated', () => {
beforeAll(async () => { beforeAll(async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })

View File

@ -8,8 +8,9 @@ import {
createContribution, createContribution,
deleteContribution, deleteContribution,
updateContribution, updateContribution,
login,
} from '@/seeds/graphql/mutations' } from '@/seeds/graphql/mutations'
import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' import { listAllContributions, listContributions } from '@/seeds/graphql/queries'
import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { cleanDB, resetToken, testEnvironment } from '@test/helpers'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { userFactory } from '@/seeds/factory/user' import { userFactory } from '@/seeds/factory/user'
@ -54,8 +55,8 @@ describe('ContributionResolver', () => {
describe('authenticated with valid user', () => { describe('authenticated with valid user', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -197,8 +198,8 @@ describe('ContributionResolver', () => {
const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de')
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await creationFactory(testEnv, bibisCreation!) await creationFactory(testEnv, bibisCreation!)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
await mutate({ await mutate({
@ -310,8 +311,8 @@ describe('ContributionResolver', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, peterLustig) await userFactory(testEnv, peterLustig)
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
result = await mutate({ result = await mutate({
@ -393,8 +394,8 @@ describe('ContributionResolver', () => {
describe('wrong user tries to update the contribution', () => { describe('wrong user tries to update the contribution', () => {
beforeAll(async () => { beforeAll(async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
}) })
@ -445,8 +446,8 @@ describe('ContributionResolver', () => {
describe('update too much so that the limit is exceeded', () => { describe('update too much so that the limit is exceeded', () => {
beforeAll(async () => { beforeAll(async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
}) })
@ -551,8 +552,8 @@ describe('ContributionResolver', () => {
const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de')
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await creationFactory(testEnv, bibisCreation!) await creationFactory(testEnv, bibisCreation!)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
await mutate({ await mutate({
@ -628,8 +629,8 @@ describe('ContributionResolver', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
await userFactory(testEnv, peterLustig) await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
result = await mutate({ result = await mutate({
@ -666,8 +667,8 @@ describe('ContributionResolver', () => {
describe('other user sends a deleteContribtuion', () => { describe('other user sends a deleteContribtuion', () => {
it('returns an error', async () => { it('returns an error', async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
await expect( await expect(
@ -700,8 +701,8 @@ describe('ContributionResolver', () => {
describe('User deletes already confirmed contribution', () => { describe('User deletes already confirmed contribution', () => {
it('throws an error', async () => { it('throws an error', async () => {
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })
await mutate({ await mutate({
@ -710,8 +711,8 @@ describe('ContributionResolver', () => {
id: result.data.createContribution.id, id: result.data.createContribution.id,
}, },
}) })
await query({ await mutate({
query: login, mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
}) })
await expect( await expect(

View File

@ -5,6 +5,8 @@ import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/help
import { userFactory } from '@/seeds/factory/user' import { userFactory } from '@/seeds/factory/user'
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
import { import {
login,
logout,
createUser, createUser,
setPassword, setPassword,
forgotPassword, forgotPassword,
@ -12,7 +14,7 @@ import {
createContribution, createContribution,
confirmContribution, confirmContribution,
} from '@/seeds/graphql/mutations' } from '@/seeds/graphql/mutations'
import { login, logout, verifyLogin, queryOptIn, searchAdminUsers } from '@/seeds/graphql/queries' import { verifyLogin, queryOptIn, searchAdminUsers } from '@/seeds/graphql/queries'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { User } from '@entity/User' import { User } from '@entity/User'
import CONFIG from '@/config' import CONFIG from '@/config'
@ -582,7 +584,7 @@ describe('UserResolver', () => {
describe('no users in database', () => { describe('no users in database', () => {
beforeAll(async () => { beforeAll(async () => {
jest.clearAllMocks() jest.clearAllMocks()
result = await query({ query: login, variables }) result = await mutate({ mutation: login, variables })
}) })
it('throws an error', () => { it('throws an error', () => {
@ -603,7 +605,7 @@ describe('UserResolver', () => {
describe('user is in database and correct login data', () => { describe('user is in database and correct login data', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
result = await query({ query: login, variables }) result = await mutate({ mutation: login, variables })
}) })
afterAll(async () => { afterAll(async () => {
@ -640,7 +642,7 @@ describe('UserResolver', () => {
describe('user is in database and wrong password', () => { describe('user is in database and wrong password', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
result = await query({ query: login, variables: { ...variables, password: 'wrong' } }) result = await mutate({ mutation: login, variables: { ...variables, password: 'wrong' } })
}) })
afterAll(async () => { afterAll(async () => {
@ -665,7 +667,7 @@ describe('UserResolver', () => {
describe('unauthenticated', () => { describe('unauthenticated', () => {
it('throws an error', async () => { it('throws an error', async () => {
resetToken() resetToken()
await expect(query({ query: logout })).resolves.toEqual( await expect(mutate({ mutation: logout })).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')], errors: [new GraphQLError('401 Unauthorized')],
}), }),
@ -681,7 +683,7 @@ describe('UserResolver', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
await query({ query: login, variables }) await mutate({ mutation: login, variables })
}) })
afterAll(async () => { afterAll(async () => {
@ -689,7 +691,7 @@ describe('UserResolver', () => {
}) })
it('returns true', async () => { it('returns true', async () => {
await expect(query({ query: logout })).resolves.toEqual( await expect(mutate({ mutation: logout })).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
data: { logout: 'true' }, data: { logout: 'true' },
errors: undefined, errors: undefined,
@ -738,7 +740,7 @@ describe('UserResolver', () => {
} }
beforeAll(async () => { beforeAll(async () => {
await query({ query: login, variables }) await mutate({ mutation: login, variables })
user = await User.find() user = await User.find()
}) })
@ -929,8 +931,8 @@ describe('UserResolver', () => {
describe('authenticated', () => { describe('authenticated', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
await query({ await mutate({
query: login, mutation: login,
variables: { variables: {
email: 'bibi@bloxberg.de', email: 'bibi@bloxberg.de',
password: 'Aa12345_', password: 'Aa12345_',
@ -1061,8 +1063,8 @@ describe('UserResolver', () => {
it('can login with new password', async () => { it('can login with new password', async () => {
await expect( await expect(
query({ mutate({
query: login, mutation: login,
variables: { variables: {
email: 'bibi@bloxberg.de', email: 'bibi@bloxberg.de',
password: 'Bb12345_', password: 'Bb12345_',
@ -1081,8 +1083,8 @@ describe('UserResolver', () => {
it('cannot login with old password', async () => { it('cannot login with old password', async () => {
await expect( await expect(
query({ mutate({
query: login, mutation: login,
variables: { variables: {
email: 'bibi@bloxberg.de', email: 'bibi@bloxberg.de',
password: 'Aa12345_', password: 'Aa12345_',
@ -1119,8 +1121,8 @@ describe('UserResolver', () => {
beforeAll(async () => { beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
await userFactory(testEnv, peterLustig) await userFactory(testEnv, peterLustig)
await query({ await mutate({
query: login, mutation: login,
variables: { variables: {
email: 'bibi@bloxberg.de', email: 'bibi@bloxberg.de',
password: 'Aa12345_', password: 'Aa12345_',

View File

@ -316,7 +316,7 @@ export class UserResolver {
} }
@Authorized([RIGHTS.LOGIN]) @Authorized([RIGHTS.LOGIN])
@Query(() => User) @Mutation(() => User)
@UseMiddleware(klicktippNewsletterStateMiddleware) @UseMiddleware(klicktippNewsletterStateMiddleware)
async login( async login(
@Args() { email, password, publisherId }: UnsecureLoginArgs, @Args() { email, password, publisherId }: UnsecureLoginArgs,
@ -377,7 +377,7 @@ export class UserResolver {
} }
@Authorized([RIGHTS.LOGOUT]) @Authorized([RIGHTS.LOGOUT])
@Query(() => String) @Mutation(() => String)
async logout(): Promise<boolean> { async logout(): Promise<boolean> {
// TODO: We dont need this anymore, but might need this in the future in oder to invalidate a valid JWT-Token. // TODO: We dont need this anymore, but might need this in the future in oder to invalidate a valid JWT-Token.
// Furthermore this hook can be useful for tracking user behaviour (did he logout or not? Warn him if he didn't on next login) // Furthermore this hook can be useful for tracking user behaviour (did he logout or not? Warn him if he didn't on next login)

View File

@ -1,6 +1,5 @@
import { ApolloServerTestClient } from 'apollo-server-testing' import { ApolloServerTestClient } from 'apollo-server-testing'
import { createContributionLink } from '@/seeds/graphql/mutations' import { login, createContributionLink } from '@/seeds/graphql/mutations'
import { login } from '@/seeds/graphql/queries'
import { ContributionLink } from '@model/ContributionLink' import { ContributionLink } from '@model/ContributionLink'
import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface' import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface'
@ -8,12 +7,12 @@ export const contributionLinkFactory = async (
client: ApolloServerTestClient, client: ApolloServerTestClient,
contributionLink: ContributionLinkInterface, contributionLink: ContributionLinkInterface,
): Promise<ContributionLink> => { ): Promise<ContributionLink> => {
const { mutate, query } = client const { mutate } = client
// login as admin // login as admin
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const user = await query({ const user = await mutate({
query: login, mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
}) })

View File

@ -2,8 +2,7 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { backendLogger as logger } from '@/server/logger' import { backendLogger as logger } from '@/server/logger'
import { adminCreateContribution, confirmContribution } from '@/seeds/graphql/mutations' import { login, adminCreateContribution, confirmContribution } from '@/seeds/graphql/mutations'
import { login } from '@/seeds/graphql/queries'
import { CreationInterface } from '@/seeds/creation/CreationInterface' import { CreationInterface } from '@/seeds/creation/CreationInterface'
import { ApolloServerTestClient } from 'apollo-server-testing' import { ApolloServerTestClient } from 'apollo-server-testing'
import { Transaction } from '@entity/Transaction' import { Transaction } from '@entity/Transaction'
@ -19,9 +18,9 @@ export const creationFactory = async (
client: ApolloServerTestClient, client: ApolloServerTestClient,
creation: CreationInterface, creation: CreationInterface,
): Promise<Contribution | void> => { ): Promise<Contribution | void> => {
const { mutate, query } = client const { mutate } = client
logger.trace('creationFactory...') logger.trace('creationFactory...')
await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } }) await mutate({ mutation: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } })
logger.trace('creationFactory... after login') logger.trace('creationFactory... after login')
// TODO it would be nice to have this mutation return the id // TODO it would be nice to have this mutation return the id
await mutate({ mutation: adminCreateContribution, variables: { ...creation } }) await mutate({ mutation: adminCreateContribution, variables: { ...creation } })

View File

@ -1,6 +1,5 @@
import { ApolloServerTestClient } from 'apollo-server-testing' import { ApolloServerTestClient } from 'apollo-server-testing'
import { createTransactionLink } from '@/seeds/graphql/mutations' import { login, createTransactionLink } from '@/seeds/graphql/mutations'
import { login } from '@/seeds/graphql/queries'
import { TransactionLinkInterface } from '@/seeds/transactionLink/TransactionLinkInterface' import { TransactionLinkInterface } from '@/seeds/transactionLink/TransactionLinkInterface'
import { transactionLinkExpireDate } from '@/graphql/resolver/TransactionLinkResolver' import { transactionLinkExpireDate } from '@/graphql/resolver/TransactionLinkResolver'
import { TransactionLink } from '@entity/TransactionLink' import { TransactionLink } from '@entity/TransactionLink'
@ -9,10 +8,13 @@ export const transactionLinkFactory = async (
client: ApolloServerTestClient, client: ApolloServerTestClient,
transactionLink: TransactionLinkInterface, transactionLink: TransactionLinkInterface,
): Promise<void> => { ): Promise<void> => {
const { mutate, query } = client const { mutate } = client
// login // login
await query({ query: login, variables: { email: transactionLink.email, password: 'Aa12345_' } }) await mutate({
mutation: login,
variables: { email: transactionLink.email, password: 'Aa12345_' },
})
const variables = { const variables = {
amount: transactionLink.amount, amount: transactionLink.amount,

View File

@ -289,3 +289,27 @@ export const adminCreateContributionMessage = gql`
} }
} }
` `
export const login = gql`
mutation ($email: String!, $password: String!, $publisherId: Int) {
login(email: $email, password: $password, publisherId: $publisherId) {
id
email
firstName
lastName
language
klickTipp {
newsletterState
}
hasElopage
publisherId
isAdmin
}
}
`
export const logout = gql`
mutation {
logout
}
`

View File

@ -1,23 +1,5 @@
import gql from 'graphql-tag' import gql from 'graphql-tag'
export const login = gql`
query ($email: String!, $password: String!, $publisherId: Int) {
login(email: $email, password: $password, publisherId: $publisherId) {
id
email
firstName
lastName
language
klickTipp {
newsletterState
}
hasElopage
publisherId
isAdmin
}
}
`
export const verifyLogin = gql` export const verifyLogin = gql`
query { query {
verifyLogin { verifyLogin {
@ -35,12 +17,6 @@ export const verifyLogin = gql`
} }
` `
export const logout = gql`
query {
logout
}
`
export const queryOptIn = gql` export const queryOptIn = gql`
query ($optIn: String!) { query ($optIn: String!) {
queryOptIn(optIn: $optIn) queryOptIn(optIn: $optIn)

View File

@ -136,3 +136,27 @@ export const createContributionMessage = gql`
} }
} }
` `
export const login = gql`
mutation($email: String!, $password: String!, $publisherId: Int) {
login(email: $email, password: $password, publisherId: $publisherId) {
email
firstName
lastName
language
klickTipp {
newsletterState
}
hasElopage
publisherId
isAdmin
creation
}
}
`
export const logout = gql`
mutation {
logout
}
`

View File

@ -1,23 +1,5 @@
import gql from 'graphql-tag' import gql from 'graphql-tag'
export const login = gql`
query($email: String!, $password: String!, $publisherId: Int) {
login(email: $email, password: $password, publisherId: $publisherId) {
email
firstName
lastName
language
klickTipp {
newsletterState
}
hasElopage
publisherId
isAdmin
creation
}
}
`
export const verifyLogin = gql` export const verifyLogin = gql`
query { query {
verifyLogin { verifyLogin {
@ -36,12 +18,6 @@ export const verifyLogin = gql`
} }
` `
export const logout = gql`
query {
logout
}
`
export const transactionsQuery = gql` export const transactionsQuery = gql`
query($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) { query($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) {
transactionList(currentPage: $currentPage, pageSize: $pageSize, order: $order) { transactionList(currentPage: $currentPage, pageSize: $pageSize, order: $order) {

View File

@ -18,6 +18,7 @@ const apolloMock = jest.fn().mockResolvedValue({
logout: 'success', logout: 'success',
}, },
}) })
const apolloQueryMock = jest.fn()
describe('DashboardLayout', () => { describe('DashboardLayout', () => {
let wrapper let wrapper
@ -40,7 +41,8 @@ describe('DashboardLayout', () => {
}, },
}, },
$apollo: { $apollo: {
query: apolloMock, mutate: apolloMock,
query: apolloQueryMock,
}, },
$store: { $store: {
state: { state: {
@ -142,7 +144,7 @@ describe('DashboardLayout', () => {
describe('update transactions', () => { describe('update transactions', () => {
beforeEach(async () => { beforeEach(async () => {
apolloMock.mockResolvedValue({ apolloQueryMock.mockResolvedValue({
data: { data: {
transactionList: { transactionList: {
balance: { balance: {
@ -163,7 +165,7 @@ describe('DashboardLayout', () => {
}) })
it('calls the API', () => { it('calls the API', () => {
expect(apolloMock).toBeCalledWith( expect(apolloQueryMock).toBeCalledWith(
expect.objectContaining({ expect.objectContaining({
variables: { variables: {
currentPage: 2, currentPage: 2,
@ -201,7 +203,7 @@ describe('DashboardLayout', () => {
describe('update transactions returns error', () => { describe('update transactions returns error', () => {
beforeEach(async () => { beforeEach(async () => {
apolloMock.mockRejectedValue({ apolloQueryMock.mockRejectedValue({
message: 'Ouch!', message: 'Ouch!',
}) })
await wrapper await wrapper

View File

@ -41,7 +41,8 @@
import Navbar from '@/components/Menu/Navbar.vue' import Navbar from '@/components/Menu/Navbar.vue'
import Sidebar from '@/components/Menu/Sidebar.vue' import Sidebar from '@/components/Menu/Sidebar.vue'
import SessionLogoutTimeout from '@/components/SessionLogoutTimeout.vue' import SessionLogoutTimeout from '@/components/SessionLogoutTimeout.vue'
import { logout, transactionsQuery } from '@/graphql/queries' import { transactionsQuery } from '@/graphql/queries'
import { logout } from '@/graphql/mutations'
import ContentFooter from '@/components/ContentFooter.vue' import ContentFooter from '@/components/ContentFooter.vue'
import { FadeTransition } from 'vue2-transitions' import { FadeTransition } from 'vue2-transitions'
import CONFIG from '@/config' import CONFIG from '@/config'
@ -75,8 +76,8 @@ export default {
methods: { methods: {
async logout() { async logout() {
this.$apollo this.$apollo
.query({ .mutate({
query: logout, mutation: logout,
}) })
.then(() => { .then(() => {
this.$store.dispatch('logout') this.$store.dispatch('logout')

View File

@ -5,7 +5,7 @@ import Login from './Login'
const localVue = global.localVue const localVue = global.localVue
const apolloQueryMock = jest.fn() const apolloMutateMock = jest.fn()
const mockStoreDispach = jest.fn() const mockStoreDispach = jest.fn()
const mockStoreCommit = jest.fn() const mockStoreCommit = jest.fn()
const mockRouterPush = jest.fn() const mockRouterPush = jest.fn()
@ -41,7 +41,7 @@ describe('Login', () => {
params: {}, params: {},
}, },
$apollo: { $apollo: {
query: apolloQueryMock, mutate: apolloMutateMock,
}, },
} }
@ -113,7 +113,7 @@ describe('Login', () => {
await wrapper.find('input[placeholder="Email"]').setValue('user@example.org') await wrapper.find('input[placeholder="Email"]').setValue('user@example.org')
await wrapper.find('input[placeholder="form.password"]').setValue('1234') await wrapper.find('input[placeholder="form.password"]').setValue('1234')
await flushPromises() await flushPromises()
apolloQueryMock.mockResolvedValue({ apolloMutateMock.mockResolvedValue({
data: { data: {
login: 'token', login: 'token',
}, },
@ -123,7 +123,7 @@ describe('Login', () => {
}) })
it('calls the API with the given data', () => { it('calls the API with the given data', () => {
expect(apolloQueryMock).toBeCalledWith( expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({ expect.objectContaining({
variables: { variables: {
email: 'user@example.org', email: 'user@example.org',
@ -175,7 +175,7 @@ describe('Login', () => {
describe('login fails', () => { describe('login fails', () => {
const createError = async (errorMessage) => { const createError = async (errorMessage) => {
apolloQueryMock.mockRejectedValue({ apolloMutateMock.mockRejectedValue({
message: errorMessage, message: errorMessage,
}) })
wrapper = Wrapper() wrapper = Wrapper()

View File

@ -43,7 +43,7 @@
import InputPassword from '@/components/Inputs/InputPassword' import InputPassword from '@/components/Inputs/InputPassword'
import InputEmail from '@/components/Inputs/InputEmail' import InputEmail from '@/components/Inputs/InputEmail'
import Message from '@/components/Message/Message' import Message from '@/components/Message/Message'
import { login } from '@/graphql/queries' import { login } from '@/graphql/mutations'
export default { export default {
name: 'Login', name: 'Login',
@ -71,14 +71,13 @@ export default {
container: this.$refs.submitButton, container: this.$refs.submitButton,
}) })
this.$apollo this.$apollo
.query({ .mutate({
query: login, mutation: login,
variables: { variables: {
email: this.form.email, email: this.form.email,
password: this.form.password, password: this.form.password,
publisherId: this.$store.state.publisherId, publisherId: this.$store.state.publisherId,
}, },
fetchPolicy: 'network-only',
}) })
.then(async (result) => { .then(async (result) => {
const { const {

View File

@ -43,6 +43,7 @@ const mocks = {
$store: { $store: {
state: { state: {
token: null, token: null,
tokenTime: null,
email: 'bibi@bloxberg.de', email: 'bibi@bloxberg.de',
}, },
}, },
@ -68,7 +69,7 @@ describe('TransactionLink', () => {
} }
describe('mount', () => { describe('mount', () => {
beforeEach(() => { beforeAll(() => {
jest.clearAllMocks() jest.clearAllMocks()
wrapper = Wrapper() wrapper = Wrapper()
}) })
@ -214,112 +215,159 @@ describe('TransactionLink', () => {
}) })
}) })
describe('token in store and own link', () => { describe('token in store', () => {
beforeEach(() => { beforeAll(() => {
mocks.$store.state.token = 'token' mocks.$store.state.token = 'token'
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
__typename: 'TransactionLink',
id: 92,
amount: '22',
memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
createdAt: '2022-03-17T16:10:28.000Z',
validUntil: transactionLinkValidExpireDate(),
redeemedAt: null,
deletedAt: null,
user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de' },
},
},
})
wrapper = Wrapper()
}) })
it('has a RedeemSelfCreator component', () => { describe('sufficient token time in store', () => {
expect(wrapper.findComponent({ name: 'RedeemSelfCreator' }).exists()).toBe(true) beforeAll(() => {
}) mocks.$store.state.tokenTime = Math.floor(Date.now() / 1000) + 20
it('has a no redeem text', () => {
expect(wrapper.findComponent({ name: 'RedeemSelfCreator' }).text()).toContain(
'gdd_per_link.no-redeem',
)
})
it.skip('has a link to transaction page', () => {
expect(wrapper.find('a[target="/transactions"]').exists()).toBe(true)
})
})
describe('valid link', () => {
beforeEach(() => {
mocks.$store.state.token = 'token'
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
__typename: 'TransactionLink',
id: 92,
amount: '22',
memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
createdAt: '2022-03-17T16:10:28.000Z',
validUntil: transactionLinkValidExpireDate(),
redeemedAt: null,
deletedAt: null,
user: { firstName: 'Peter', publisherId: 0, email: 'peter@listig.de' },
},
},
})
wrapper = Wrapper()
})
it('has a RedeemValid component', () => {
expect(wrapper.findComponent({ name: 'RedeemValid' }).exists()).toBe(true)
})
it('has a button with redeem text', () => {
expect(wrapper.findComponent({ name: 'RedeemValid' }).find('button').text()).toBe(
'gdd_per_link.redeem',
)
})
describe('redeem link with success', () => {
beforeEach(async () => {
apolloMutateMock.mockResolvedValue()
await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click')
}) })
it('calls the API', () => { describe('own link', () => {
expect(apolloMutateMock).toBeCalledWith( beforeAll(() => {
expect.objectContaining({ apolloQueryMock.mockResolvedValue({
mutation: redeemTransactionLink, data: {
variables: { queryTransactionLink: {
code: 'some-code', __typename: 'TransactionLink',
id: 92,
amount: '22',
memo:
'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
createdAt: '2022-03-17T16:10:28.000Z',
validUntil: transactionLinkValidExpireDate(),
redeemedAt: null,
deletedAt: null,
user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de' },
},
}, },
}), })
) wrapper = Wrapper()
})
it('has a RedeemSelfCreator component', () => {
expect(wrapper.findComponent({ name: 'RedeemSelfCreator' }).exists()).toBe(true)
})
it('has a no redeem text', () => {
expect(wrapper.findComponent({ name: 'RedeemSelfCreator' }).text()).toContain(
'gdd_per_link.no-redeem',
)
})
it.skip('has a link to transaction page', () => {
expect(wrapper.find('a[target="/transactions"]').exists()).toBe(true)
})
}) })
it('toasts a success message', () => { describe('valid link', () => {
expect(mocks.$t).toBeCalledWith('gdd_per_link.redeem') beforeAll(() => {
expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.redeemed; ') apolloQueryMock.mockResolvedValue({
}) data: {
queryTransactionLink: {
__typename: 'TransactionLink',
id: 92,
amount: '22',
memo:
'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
createdAt: '2022-03-17T16:10:28.000Z',
validUntil: transactionLinkValidExpireDate(),
redeemedAt: null,
deletedAt: null,
user: { firstName: 'Peter', publisherId: 0, email: 'peter@listig.de' },
},
},
})
wrapper = Wrapper()
})
it('pushes the route to overview', () => { it('has a RedeemValid component', () => {
expect(routerPushMock).toBeCalledWith('/overview') expect(wrapper.findComponent({ name: 'RedeemValid' }).exists()).toBe(true)
})
it('has a button with redeem text', () => {
expect(wrapper.findComponent({ name: 'RedeemValid' }).find('button').text()).toBe(
'gdd_per_link.redeem',
)
})
describe('redeem link with success', () => {
beforeAll(async () => {
apolloMutateMock.mockResolvedValue()
await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click')
})
it('calls the API', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
mutation: redeemTransactionLink,
variables: {
code: 'some-code',
},
}),
)
})
it('toasts a success message', () => {
expect(mocks.$t).toBeCalledWith('gdd_per_link.redeem')
expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.redeemed; ')
})
it('pushes the route to overview', () => {
expect(routerPushMock).toBeCalledWith('/overview')
})
})
describe('redeem link with error', () => {
beforeAll(async () => {
apolloMutateMock.mockRejectedValue({ message: 'Oh Noo!' })
await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click')
})
it('toasts an error message', () => {
expect(toastErrorSpy).toBeCalledWith('Oh Noo!')
})
it('pushes the route to overview', () => {
expect(routerPushMock).toBeCalledWith('/overview')
})
})
}) })
}) })
describe('redeem link with error', () => { describe('no sufficient token time in store', () => {
beforeEach(async () => { beforeAll(() => {
apolloMutateMock.mockRejectedValue({ message: 'Oh Noo!' }) mocks.$store.state.tokenTime = 1665125185
await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click') apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
__typename: 'TransactionLink',
id: 92,
amount: '22',
memo:
'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
createdAt: '2022-03-17T16:10:28.000Z',
validUntil: transactionLinkValidExpireDate(),
redeemedAt: null,
deletedAt: null,
user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de' },
},
},
})
wrapper = Wrapper()
}) })
it('toasts an error message', () => { it('has a RedeemLoggedOut component', () => {
expect(toastErrorSpy).toBeCalledWith('Oh Noo!') expect(wrapper.findComponent({ name: 'RedeemLoggedOut' }).exists()).toBe(true)
}) })
it('pushes the route to overview', () => { it('has a link to register with code', () => {
expect(routerPushMock).toBeCalledWith('/overview') expect(wrapper.find('a[href="/register/some-code"]').exists()).toBe(true)
})
it('has a link to login with code', () => {
expect(wrapper.find('a[href="/login/some-code"]').exists()).toBe(true)
}) })
}) })
}) })

View File

@ -103,6 +103,12 @@ export default {
isContributionLink() { isContributionLink() {
return this.$route.params.code.search(/^CL-/) === 0 return this.$route.params.code.search(/^CL-/) === 0
}, },
tokenExpiresInSeconds() {
const remainingSecs = Math.floor(
(new Date(this.$store.state.tokenTime * 1000).getTime() - new Date().getTime()) / 1000,
)
return remainingSecs <= 0 ? 0 : remainingSecs
},
itemType() { itemType() {
// link is deleted: at, from // link is deleted: at, from
if (this.linkData.deletedAt) { if (this.linkData.deletedAt) {
@ -130,7 +136,9 @@ export default {
return `TEXT` return `TEXT`
} }
if (this.$store.state.token) { if (this.$store.state.token && this.$store.state.tokenTime) {
if (this.tokenExpiresInSeconds < 5) return `LOGGED_OUT`
// logged in, nicht berechtigt einzulösen, eigener link // logged in, nicht berechtigt einzulösen, eigener link
if (this.linkData.user && this.$store.state.email === this.linkData.user.email) { if (this.linkData.user && this.$store.state.email === this.linkData.user.email) {
return `SELF_CREATOR` return `SELF_CREATOR`