test transaction link page

This commit is contained in:
Moriz Wahl 2022-03-21 16:25:17 +01:00
parent c57b40adc1
commit 5baa14b359
2 changed files with 338 additions and 64 deletions

View File

@ -1,83 +1,360 @@
import { mount } from '@vue/test-utils' import { mount } from '@vue/test-utils'
import TransactionLink from './TransactionLink' import TransactionLink from './TransactionLink'
import { queryTransactionLink } from '@/graphql/queries' import { queryTransactionLink } from '@/graphql/queries'
import { redeemTransactionLink } from '@/graphql/mutations'
import { toastSuccessSpy, toastErrorSpy } from '@test/testSetup'
const localVue = global.localVue const localVue = global.localVue
const errorHandler = jest.fn()
const apolloQueryMock = jest.fn() const apolloQueryMock = jest.fn()
const apolloMutateMock = jest.fn()
const routerPushMock = jest.fn()
localVue.config.errorHandler = errorHandler const now = new Date().toISOString()
const transactionLinkValidExpireDate = () => {
const validUntil = new Date()
return new Date(validUntil.setDate(new Date().getDate() + 14)).toISOString()
}
apolloQueryMock.mockResolvedValue({ apolloQueryMock.mockResolvedValue({
data: { data: {
listTransactionLinks: [ queryTransactionLink: {
{ id: 92,
id: 92, amount: '22',
amount: '22', memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ', createdAt: '2022-03-17T16:10:28.000Z',
createdAt: '2022-03-17T16:10:28.000Z', validUntil: transactionLinkValidExpireDate(),
validUntil: '2022-03-31T16:10:28.000Z', redeemedAt: '2022-03-18T10:08:43.000Z',
redeemedAt: '2022-03-18T10:08:43.000Z', deletedAt: null,
deletedAt: null, user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de' },
user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de', __typename: 'User' }, },
},
],
}, },
}) })
const createMockObject = (code) => { const mocks = {
return { $t: jest.fn((t, obj = null) => (obj ? [t, obj.date].join('; ') : t)),
localVue, $store: {
mocks: { state: {
$t: jest.fn((t) => t), token: null,
$i18n: { email: 'bibi@bloxberg.de',
locale: () => 'en',
},
$store: {
state: {
email: 'bibi@bloxberg.de',
},
},
$apollo: {
query: apolloQueryMock,
},
$route: {
params: {
code: 'c0000c0000c0000',
},
},
}, },
} },
$apollo: {
query: apolloQueryMock,
mutate: apolloMutateMock,
},
$route: {
params: {
code: 'some-code',
},
},
$router: {
push: routerPushMock,
},
} }
describe('TransactionLink', () => { describe('TransactionLink', () => {
let wrapper let wrapper
const Wrapper = (functionN) => { const Wrapper = () => {
return mount(TransactionLink, functionN) return mount(TransactionLink, { localVue, mocks })
} }
describe('mount', () => { describe('mount', () => {
beforeEach(() => { beforeEach(() => {
wrapper = Wrapper(createMockObject()) jest.clearAllMocks()
wrapper = Wrapper()
}) })
it('renders the component', () => { it('renders the component', () => {
expect(wrapper.find('div.show-transaction-link-informations').exists()).toBeTruthy() expect(wrapper.find('div.show-transaction-link-informations').exists()).toBe(true)
}) })
it('calls the queryTransactionLink query', () => { it('calls the queryTransactionLink query', () => {
expect(apolloQueryMock).toBeCalledWith({ expect(apolloQueryMock).toBeCalledWith({
query: queryTransactionLink, query: queryTransactionLink,
variables: { variables: {
code: 'c0000c0000c0000', code: 'some-code',
}, },
}) })
}) })
it('has link one information link data', () => { describe('deleted link', () => {
expect(apolloQueryMock.mockResolvedValue).toHaveLength(1) beforeEach(() => {
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
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: '2022-03-18T10:08:43.000Z',
deletedAt: now,
user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de' },
},
},
})
wrapper = Wrapper()
})
it('has a component RedeemedTextBox', () => {
expect(wrapper.findComponent({ name: 'RedeemedTextBox' }).exists()).toBe(true)
})
it('has a link deleted text in text box', () => {
expect(wrapper.findComponent({ name: 'RedeemedTextBox' }).text()).toContain(
'gdd_per_link.link-deleted; ' + now,
)
})
})
describe('expired link', () => {
beforeEach(() => {
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
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: '2020-03-18T10:08:43.000Z',
redeemedAt: '2022-03-18T10:08:43.000Z',
deletedAt: null,
user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de' },
},
},
})
wrapper = Wrapper()
})
it('has a component RedeemedTextBox', () => {
expect(wrapper.findComponent({ name: 'RedeemedTextBox' }).exists()).toBe(true)
})
it('has a link deleted text in text box', () => {
expect(wrapper.findComponent({ name: 'RedeemedTextBox' }).text()).toContain(
'gdd_per_link.link-expired; 2020-03-18T10:08:43.000Z',
)
})
})
describe('redeemed link', () => {
beforeEach(() => {
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
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: '2022-03-18T10:08:43.000Z',
deletedAt: null,
user: { firstName: 'Bibi', publisherId: 0, email: 'bibi@bloxberg.de' },
},
},
})
wrapper = Wrapper()
})
it('has a component RedeemedTextBox', () => {
expect(wrapper.findComponent({ name: 'RedeemedTextBox' }).exists()).toBe(true)
})
it('has a link deleted text in text box', () => {
expect(wrapper.findComponent({ name: 'RedeemedTextBox' }).text()).toContain(
'gdd_per_link.redeemed-at; 2022-03-18T10:08:43.000Z',
)
})
})
describe('no token in store', () => {
beforeEach(() => {
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
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 RedeemLoggedOut component', () => {
expect(wrapper.findComponent({ name: 'RedeemLoggedOut' }).exists()).toBe(true)
})
it('has a link to register with code', () => {
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)
})
})
describe('token in store and own link', () => {
beforeEach(() => {
mocks.$store.state.token = 'token'
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
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('has a link to transaction page', () => {
expect(wrapper.find('a[to="/transactions"]').exists()).toBe(true)
})
})
describe('valid link', () => {
beforeEach(() => {
mocks.$store.state.token = 'token'
apolloQueryMock.mockResolvedValue({
data: {
queryTransactionLink: {
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', () => {
let spy
beforeEach(async () => {
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
apolloMutateMock.mockResolvedValue()
spy.mockImplementation(() => Promise.resolve(true))
await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click')
})
it('opens the modal', () => {
expect(spy).toBeCalledWith('gdd_per_link.redeem-text')
})
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.redeemed', { n: '22' })
expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.redeemed; ')
})
it('pushes the route to overview', () => {
expect(routerPushMock).toBeCalledWith('/overview')
})
})
describe('cancel redeem link', () => {
let spy
beforeEach(async () => {
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
apolloMutateMock.mockResolvedValue()
spy.mockImplementation(() => Promise.resolve(false))
await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click')
})
it('does not call the API', () => {
expect(apolloMutateMock).not.toBeCalled()
})
it('does not toasts a success message', () => {
expect(mocks.$t).not.toBeCalledWith('gdd_per_link.redeemed', { n: '22' })
expect(toastSuccessSpy).not.toBeCalled()
})
it('does not push the route', () => {
expect(routerPushMock).not.toBeCalled()
})
})
describe('redeem link with error', () => {
let spy
beforeEach(async () => {
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
apolloMutateMock.mockRejectedValue({ message: 'Oh Noo!' })
spy.mockImplementation(() => Promise.resolve(true))
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('error on transaction link query', () => {
beforeEach(() => {
apolloQueryMock.mockRejectedValue({ message: 'Ouchh!' })
wrapper = Wrapper()
})
it('toasts an error message', () => {
expect(toastErrorSpy).toBeCalledWith('Ouchh!')
})
}) })
}) })
}) })

View File

@ -65,9 +65,8 @@ export default {
.then((result) => { .then((result) => {
this.linkData = result.data.queryTransactionLink this.linkData = result.data.queryTransactionLink
}) })
.catch(() => { .catch((err) => {
this.itemType = 'X4' this.toastError(err.message)
this.linkData.deletedAt = true
}) })
}, },
redeemLink(amount) { redeemLink(amount) {
@ -97,7 +96,6 @@ export default {
}, },
computed: { computed: {
itemType() { itemType() {
// logged out
// link wurde gelöscht: am, von // link wurde gelöscht: am, von
if (this.linkData.deletedAt) { if (this.linkData.deletedAt) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties // eslint-disable-next-line vue/no-side-effects-in-computed-properties
@ -105,24 +103,23 @@ export default {
date: this.linkData.deletedAt, date: this.linkData.deletedAt,
}) })
return `TEXT` return `TEXT`
} else { }
// link ist abgelaufen, nicht gelöscht // link ist abgelaufen, nicht gelöscht
if (new Date(this.linkData.validUntil) < new Date()) { if (new Date(this.linkData.validUntil) < new Date()) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties // eslint-disable-next-line vue/no-side-effects-in-computed-properties
this.redeemedBoxText = this.$t('gdd_per_link.link-expired', { this.redeemedBoxText = this.$t('gdd_per_link.link-expired', {
date: this.linkData.validUntil, date: this.linkData.validUntil,
}) })
return `TEXT` return `TEXT`
} }
// der link wurde eingelöst, nicht gelöscht // der link wurde eingelöst, nicht gelöscht
if (this.linkData.redeemedAt) { if (this.linkData.redeemedAt) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties // eslint-disable-next-line vue/no-side-effects-in-computed-properties
this.redeemedBoxText = this.$t('gdd_per_link.redeemed-at', { this.redeemedBoxText = this.$t('gdd_per_link.redeemed-at', {
date: this.linkData.redeemedAt, date: this.linkData.redeemedAt,
}) })
return `TEXT` return `TEXT`
}
} }
if (this.$store.state.token) { if (this.$store.state.token) {