mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge branch 'master' into fix-gdt-error
This commit is contained in:
commit
3d4ee1de9f
@ -53,4 +53,5 @@ export enum RIGHTS {
|
||||
ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE',
|
||||
DENY_CONTRIBUTION = 'DENY_CONTRIBUTION',
|
||||
ADMIN_OPEN_CREATIONS = 'ADMIN_OPEN_CREATIONS',
|
||||
ADMIN_LIST_ALL_CONTRIBUTION_MESSAGES = 'ADMIN_LIST_ALL_CONTRIBUTION_MESSAGES',
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { ArgsType, Field, Int, InputType } from 'type-graphql'
|
||||
|
||||
import { ContributionMessageType } from '@enum/ContributionMessageType'
|
||||
|
||||
@InputType()
|
||||
@ArgsType()
|
||||
export class ContributionMessageArgs {
|
||||
@ -8,4 +10,7 @@ export class ContributionMessageArgs {
|
||||
|
||||
@Field(() => String)
|
||||
message: string
|
||||
|
||||
@Field(() => ContributionMessageType, { defaultValue: ContributionMessageType.DIALOG })
|
||||
messageType: ContributionMessageType
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { registerEnumType } from 'type-graphql'
|
||||
export enum ContributionMessageType {
|
||||
HISTORY = 'HISTORY',
|
||||
DIALOG = 'DIALOG',
|
||||
MODERATOR = 'MODERATOR', // messages for moderator communication, can only be seen by moderators
|
||||
}
|
||||
|
||||
registerEnumType(ContributionMessageType, {
|
||||
@ -20,7 +20,7 @@ import {
|
||||
createContributionMessage,
|
||||
login,
|
||||
} from '@/seeds/graphql/mutations'
|
||||
import { listContributionMessages } from '@/seeds/graphql/queries'
|
||||
import { listContributionMessages, adminListContributionMessages } from '@/seeds/graphql/queries'
|
||||
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||
|
||||
@ -217,6 +217,33 @@ describe('ContributionMessageResolver', () => {
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('contribution message type MODERATOR', () => {
|
||||
it('creates ContributionMessage', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminCreateContributionMessage,
|
||||
variables: {
|
||||
contributionId: result.data.createContribution.id,
|
||||
message: 'Internal moderator communication',
|
||||
messageType: 'MODERATOR',
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
adminCreateContributionMessage: expect.objectContaining({
|
||||
id: expect.any(Number),
|
||||
message: 'Internal moderator communication',
|
||||
type: 'MODERATOR',
|
||||
userFirstName: 'Peter',
|
||||
userLastName: 'Lustig',
|
||||
}),
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -385,7 +412,7 @@ describe('ContributionMessageResolver', () => {
|
||||
resetToken()
|
||||
})
|
||||
|
||||
it('returns a list of contributionmessages', async () => {
|
||||
it('returns a list of contributionmessages without type MODERATOR', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: listContributionMessages,
|
||||
@ -419,4 +446,96 @@ describe('ContributionMessageResolver', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('adminListContributionMessages', () => {
|
||||
describe('unauthenticated', () => {
|
||||
it('returns an error', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminListContributionMessages,
|
||||
variables: { contributionId: 1 },
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('401 Unauthorized')],
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('authenticated as user', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||
})
|
||||
})
|
||||
|
||||
it('returns an error', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminListContributionMessages,
|
||||
variables: { contributionId: 1 },
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('401 Unauthorized')],
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('authenticated as admin', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
resetToken()
|
||||
})
|
||||
|
||||
it('returns a list of contributionmessages with type MODERATOR', async () => {
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminListContributionMessages,
|
||||
variables: { contributionId: result.data.createContribution.id },
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
adminListContributionMessages: {
|
||||
count: 3,
|
||||
messages: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: expect.any(Number),
|
||||
message: 'Admin Test',
|
||||
type: 'DIALOG',
|
||||
userFirstName: 'Peter',
|
||||
userLastName: 'Lustig',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: expect.any(Number),
|
||||
message: 'User Test',
|
||||
type: 'DIALOG',
|
||||
userFirstName: 'Bibi',
|
||||
userLastName: 'Bloxberg',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: expect.any(Number),
|
||||
message: 'Internal moderator communication',
|
||||
type: 'MODERATOR',
|
||||
userFirstName: 'Peter',
|
||||
userLastName: 'Lustig',
|
||||
}),
|
||||
]),
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -8,8 +8,8 @@ import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type
|
||||
|
||||
import { ContributionMessageArgs } from '@arg/ContributionMessageArgs'
|
||||
import { Paginated } from '@arg/Paginated'
|
||||
import { ContributionMessageType } from '@enum/ContributionMessageType'
|
||||
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||
import { ContributionMessageType } from '@enum/MessageType'
|
||||
import { Order } from '@enum/Order'
|
||||
import { ContributionMessage, ContributionMessageListResult } from '@model/ContributionMessage'
|
||||
|
||||
@ -22,6 +22,8 @@ import {
|
||||
import { Context, getUser } from '@/server/context'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { findContributionMessages } from './util/findContributionMessages'
|
||||
|
||||
@Resolver()
|
||||
export class ContributionMessageResolver {
|
||||
@Authorized([RIGHTS.CREATE_CONTRIBUTION_MESSAGE])
|
||||
@ -82,16 +84,35 @@ export class ContributionMessageResolver {
|
||||
@Args()
|
||||
{ currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
|
||||
): Promise<ContributionMessageListResult> {
|
||||
const [contributionMessages, count] = await getConnection()
|
||||
.createQueryBuilder()
|
||||
.select('cm')
|
||||
.from(DbContributionMessage, 'cm')
|
||||
.leftJoinAndSelect('cm.user', 'u')
|
||||
.where({ contributionId })
|
||||
.orderBy('cm.createdAt', order)
|
||||
.limit(pageSize)
|
||||
.offset((currentPage - 1) * pageSize)
|
||||
.getManyAndCount()
|
||||
const [contributionMessages, count] = await findContributionMessages({
|
||||
contributionId,
|
||||
currentPage,
|
||||
pageSize,
|
||||
order,
|
||||
})
|
||||
|
||||
return {
|
||||
count,
|
||||
messages: contributionMessages.map(
|
||||
(message) => new ContributionMessage(message, message.user),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.ADMIN_LIST_ALL_CONTRIBUTION_MESSAGES])
|
||||
@Query(() => ContributionMessageListResult)
|
||||
async adminListContributionMessages(
|
||||
@Arg('contributionId', () => Int) contributionId: number,
|
||||
@Args()
|
||||
{ currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
|
||||
): Promise<ContributionMessageListResult> {
|
||||
const [contributionMessages, count] = await findContributionMessages({
|
||||
contributionId,
|
||||
currentPage,
|
||||
pageSize,
|
||||
order,
|
||||
showModeratorType: true,
|
||||
})
|
||||
|
||||
return {
|
||||
count,
|
||||
@ -104,7 +125,7 @@ export class ContributionMessageResolver {
|
||||
@Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTION_MESSAGE])
|
||||
@Mutation(() => ContributionMessage)
|
||||
async adminCreateContributionMessage(
|
||||
@Args() { contributionId, message }: ContributionMessageArgs,
|
||||
@Args() { contributionId, message, messageType }: ContributionMessageArgs,
|
||||
@Ctx() context: Context,
|
||||
): Promise<ContributionMessage> {
|
||||
const moderator = getUser(context)
|
||||
@ -133,7 +154,7 @@ export class ContributionMessageResolver {
|
||||
contributionMessage.createdAt = new Date()
|
||||
contributionMessage.message = message
|
||||
contributionMessage.userId = moderator.id
|
||||
contributionMessage.type = ContributionMessageType.DIALOG
|
||||
contributionMessage.type = messageType
|
||||
contributionMessage.isModerator = true
|
||||
await queryRunner.manager.insert(DbContributionMessage, contributionMessage)
|
||||
|
||||
|
||||
@ -11,9 +11,9 @@ import { AdminCreateContributionArgs } from '@arg/AdminCreateContributionArgs'
|
||||
import { AdminUpdateContributionArgs } from '@arg/AdminUpdateContributionArgs'
|
||||
import { ContributionArgs } from '@arg/ContributionArgs'
|
||||
import { Paginated } from '@arg/Paginated'
|
||||
import { ContributionMessageType } from '@enum/ContributionMessageType'
|
||||
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||
import { ContributionType } from '@enum/ContributionType'
|
||||
import { ContributionMessageType } from '@enum/MessageType'
|
||||
import { Order } from '@enum/Order'
|
||||
import { TransactionTypeId } from '@enum/TransactionTypeId'
|
||||
import { AdminUpdateContribution } from '@model/AdminUpdateContribution'
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import { In } from '@dbTools/typeorm'
|
||||
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
|
||||
|
||||
import { ContributionMessageType } from '@enum/ContributionMessageType'
|
||||
import { Order } from '@enum/Order'
|
||||
|
||||
interface FindContributionMessagesOptions {
|
||||
contributionId: number
|
||||
pageSize: number
|
||||
currentPage: number
|
||||
order: Order
|
||||
showModeratorType?: boolean
|
||||
}
|
||||
|
||||
export const findContributionMessages = async (
|
||||
options: FindContributionMessagesOptions,
|
||||
): Promise<[DbContributionMessage[], number]> => {
|
||||
const { contributionId, pageSize, currentPage, order, showModeratorType } = options
|
||||
|
||||
const messageTypes = [ContributionMessageType.DIALOG, ContributionMessageType.HISTORY]
|
||||
|
||||
if (showModeratorType) messageTypes.push(ContributionMessageType.MODERATOR)
|
||||
|
||||
return DbContributionMessage.findAndCount({
|
||||
where: {
|
||||
contributionId,
|
||||
type: In(messageTypes),
|
||||
},
|
||||
relations: ['user'],
|
||||
order: {
|
||||
createdAt: order,
|
||||
},
|
||||
skip: (currentPage - 1) * pageSize,
|
||||
take: pageSize,
|
||||
})
|
||||
}
|
||||
@ -284,8 +284,12 @@ export const createContributionMessage = gql`
|
||||
`
|
||||
|
||||
export const adminCreateContributionMessage = gql`
|
||||
mutation ($contributionId: Int!, $message: String!) {
|
||||
adminCreateContributionMessage(contributionId: $contributionId, message: $message) {
|
||||
mutation ($contributionId: Int!, $message: String!, $messageType: ContributionMessageType) {
|
||||
adminCreateContributionMessage(
|
||||
contributionId: $contributionId
|
||||
message: $message
|
||||
messageType: $messageType
|
||||
) {
|
||||
id
|
||||
message
|
||||
createdAt
|
||||
|
||||
@ -349,6 +349,29 @@ export const listContributionMessages = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export const adminListContributionMessages = gql`
|
||||
query ($contributionId: Int!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) {
|
||||
adminListContributionMessages(
|
||||
contributionId: $contributionId
|
||||
pageSize: $pageSize
|
||||
currentPage: $currentPage
|
||||
order: $order
|
||||
) {
|
||||
count
|
||||
messages {
|
||||
id
|
||||
message
|
||||
createdAt
|
||||
updatedAt
|
||||
type
|
||||
userFirstName
|
||||
userLastName
|
||||
userId
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const user = gql`
|
||||
query ($identifier: String!) {
|
||||
user(identifier: $identifier) {
|
||||
|
||||
@ -1 +1,2 @@
|
||||
node_modules
|
||||
playwright
|
||||
|
||||
@ -2,13 +2,13 @@ module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
cypress: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['cypress', 'prettier', '@typescript-eslint' /*, 'jest' */],
|
||||
extends: [
|
||||
'standard',
|
||||
'eslint:recommended',
|
||||
'plugin:cypress/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
],
|
||||
|
||||
@ -6,7 +6,7 @@ let emailLink: string
|
||||
|
||||
async function setupNodeEvents(
|
||||
on: Cypress.PluginEvents,
|
||||
config: Cypress.PluginConfigOptions
|
||||
config: Cypress.PluginConfigOptions,
|
||||
): Promise<Cypress.PluginConfigOptions> {
|
||||
await addCucumberPreprocessorPlugin(on, config)
|
||||
|
||||
@ -14,7 +14,7 @@ async function setupNodeEvents(
|
||||
'file:preprocessor',
|
||||
browserify(config, {
|
||||
typescript: require.resolve('typescript'),
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
on('task', {
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
export class OverviewPage {
|
||||
navbarName = '[data-test="navbar-item-username"]'
|
||||
rightLastTransactionsList = '.rightside-last-transactions'
|
||||
|
||||
|
||||
goto() {
|
||||
cy.visit('/overview')
|
||||
|
||||
@ -14,9 +14,7 @@ export class ResetPasswordPage {
|
||||
}
|
||||
|
||||
repeatNewPassword(password: string) {
|
||||
cy.get(this.newPasswordRepeatInput)
|
||||
.find('input[type=password]')
|
||||
.type(password)
|
||||
cy.get(this.newPasswordRepeatInput).find('input[type=password]').type(password)
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
@ -5,30 +5,21 @@ export class SendPage {
|
||||
submitBtn = '.btn-gradido'
|
||||
|
||||
enterReceiverEmail(email: string) {
|
||||
cy.get('[data-test="input-identifier"]').find('input')
|
||||
.clear()
|
||||
.type(email)
|
||||
cy.get('[data-test="input-identifier"]').find('input').clear().type(email)
|
||||
return this
|
||||
}
|
||||
|
||||
enterAmount(amount: string) {
|
||||
cy.get('[data-test="input-amount"]')
|
||||
.find('input')
|
||||
.clear()
|
||||
.type(amount)
|
||||
cy.get('[data-test="input-amount"]').find('input').clear().type(amount)
|
||||
return this
|
||||
}
|
||||
|
||||
enterMemoText(text: string) {
|
||||
cy.get('[data-test="input-textarea"]')
|
||||
.find('textarea')
|
||||
.clear()
|
||||
.type(text)
|
||||
cy.get('[data-test="input-textarea"]').find('textarea').clear().type(text)
|
||||
return this
|
||||
}
|
||||
|
||||
submit() {
|
||||
cy.get(this.submitBtn)
|
||||
.click()
|
||||
cy.get(this.submitBtn).click()
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,10 +8,7 @@ export class UserEMailSite {
|
||||
emailSubject = '.subject'
|
||||
|
||||
openRecentPasswordResetEMail() {
|
||||
cy.get(this.emailList)
|
||||
.find('email-item')
|
||||
.filter(':contains(asswor)')
|
||||
.click()
|
||||
cy.get(this.emailList).find('email-item').filter(':contains(asswor)').click()
|
||||
expect(cy.get(this.emailSubject)).to('contain', 'asswor')
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import './e2e'
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface Chainable<Subject> {
|
||||
login(email: string, password: string): Chainable<any>
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'
|
||||
import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
|
||||
import { OverviewPage } from '../../e2e/models/OverviewPage'
|
||||
import { SideNavMenu } from '../../e2e/models/SideNavMenu'
|
||||
import { Toasts } from '../../e2e/models/Toasts'
|
||||
@ -9,12 +9,9 @@ Given('the user navigates to page {string}', (page: string) => {
|
||||
|
||||
// login related
|
||||
|
||||
Given(
|
||||
'the user is logged in as {string} {string}',
|
||||
(email: string, password: string) => {
|
||||
cy.login(email, password)
|
||||
}
|
||||
)
|
||||
Given('the user is logged in as {string} {string}', (email: string, password: string) => {
|
||||
cy.login(email, password)
|
||||
})
|
||||
|
||||
Then('the user is logged in with username {string}', (username: string) => {
|
||||
const overviewPage = new OverviewPage()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { And, Then, When } from '@badeball/cypress-cucumber-preprocessor'
|
||||
import { Then, When } from '@badeball/cypress-cucumber-preprocessor'
|
||||
import { OverviewPage } from '../../e2e/models/OverviewPage'
|
||||
import { ResetPasswordPage } from '../../e2e/models/ResetPasswordPage'
|
||||
import { UserEMailSite } from '../../e2e/models/UserEMailSite'
|
||||
@ -23,13 +23,15 @@ Then('the user receives an e-mail containing the {string} link', (linkName: stri
|
||||
linkPattern = /\/overview/
|
||||
break
|
||||
default:
|
||||
throw new Error(`Error in "Then the user receives an e-mail containing the {string} link" step: incorrect linkname string "${linkName}"`)
|
||||
throw new Error(
|
||||
`Error in "Then the user receives an e-mail containing the {string} link" step: incorrect linkname string "${linkName}"`,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
cy.origin(
|
||||
Cypress.env('mailserverURL'),
|
||||
{ args: { emailSubject, linkPattern, userEMailSite } },
|
||||
({ emailSubject, linkPattern, userEMailSite }) => {
|
||||
({ emailSubject, linkPattern, userEMailSite }) => {
|
||||
cy.visit('/') // navigate to user's e-mail site (on fake mail server)
|
||||
cy.get(userEMailSite.emailInbox).should('be.visible')
|
||||
|
||||
@ -39,11 +41,9 @@ Then('the user receives an e-mail containing the {string} link', (linkName: stri
|
||||
.first()
|
||||
.click()
|
||||
|
||||
cy.get(userEMailSite.emailMeta)
|
||||
.find(userEMailSite.emailSubject)
|
||||
.contains(emailSubject)
|
||||
cy.get(userEMailSite.emailMeta).find(userEMailSite.emailSubject).contains(emailSubject)
|
||||
|
||||
cy.get('.email-content', { timeout: 2000})
|
||||
cy.get('.email-content', { timeout: 2000 })
|
||||
.find('.plain-text')
|
||||
.contains(linkPattern)
|
||||
.invoke('text')
|
||||
@ -51,41 +51,42 @@ Then('the user receives an e-mail containing the {string} link', (linkName: stri
|
||||
const emailLink = text.match(linkPattern)[0]
|
||||
cy.task('setEmailLink', emailLink)
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
And('the user receives the transaction e-mail about {string} GDD from {string}', (amount: string, senderName:string) => {
|
||||
cy.origin(
|
||||
Cypress.env('mailserverURL'),
|
||||
{ args: { amount, senderName, userEMailSite } },
|
||||
({ amount, senderName, userEMailSite }) => {
|
||||
const subject = `${senderName} hat dir ${amount} Gradido gesendet`
|
||||
const linkPattern = /\/transactions/
|
||||
cy.visit('/')
|
||||
cy.get(userEMailSite.emailInbox).should('be.visible')
|
||||
When(
|
||||
'the user receives the transaction e-mail about {string} GDD from {string}',
|
||||
(amount: string, senderName: string) => {
|
||||
cy.origin(
|
||||
Cypress.env('mailserverURL'),
|
||||
{ args: { amount, senderName, userEMailSite } },
|
||||
({ amount, senderName, userEMailSite }) => {
|
||||
const subject = `${senderName} hat dir ${amount} Gradido gesendet`
|
||||
const linkPattern = /\/transactions/
|
||||
cy.visit('/')
|
||||
cy.get(userEMailSite.emailInbox).should('be.visible')
|
||||
|
||||
cy.get(userEMailSite.emailList)
|
||||
.find('.email-item')
|
||||
.filter(`:contains(${subject})`)
|
||||
.first()
|
||||
.click()
|
||||
|
||||
cy.get(userEMailSite.emailMeta)
|
||||
.find(userEMailSite.emailSubject)
|
||||
.contains(subject)
|
||||
|
||||
cy.get('.email-content', { timeout: 2000})
|
||||
.find('.plain-text')
|
||||
.contains(linkPattern)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
const emailLink = text.match(linkPattern)[0]
|
||||
cy.task('setEmailLink', emailLink)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
cy.get(userEMailSite.emailList)
|
||||
.find('.email-item')
|
||||
.filter(`:contains(${subject})`)
|
||||
.first()
|
||||
.click()
|
||||
|
||||
cy.get(userEMailSite.emailMeta).find(userEMailSite.emailSubject).contains(subject)
|
||||
|
||||
cy.get('.email-content', { timeout: 2000 })
|
||||
.find('.plain-text')
|
||||
.contains(linkPattern)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
const emailLink = text.match(linkPattern)[0]
|
||||
cy.task('setEmailLink', emailLink)
|
||||
})
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
When('the user opens the {string} link in the browser', (linkName: string) => {
|
||||
const resetPasswordPage = new ResetPasswordPage()
|
||||
@ -101,10 +102,13 @@ When('the user opens the {string} link in the browser', (linkName: string) => {
|
||||
cy.get(resetPasswordPage.newPasswordInput).should('be.visible')
|
||||
break
|
||||
case 'transaction':
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const overviewPage = new OverviewPage()
|
||||
cy.get(overviewPage.rightLastTransactionsList).should('be.visible')
|
||||
break
|
||||
default:
|
||||
throw new Error(`Error in "Then the user receives an e-mail containing the {string} link" step: incorrect link name string "${linkName}"`)
|
||||
throw new Error(
|
||||
`Error in "Then the user receives an e-mail containing the {string} link" step: incorrect link name string "${linkName}"`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@ -9,7 +9,7 @@ When(
|
||||
sendPage.enterReceiverEmail(email)
|
||||
sendPage.enterAmount(amount)
|
||||
sendPage.enterMemoText(memoText)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
And('the user submits the send form', () => {
|
||||
@ -17,17 +17,25 @@ And('the user submits the send form', () => {
|
||||
cy.get(sendPage.confirmationBox).should('be.visible')
|
||||
})
|
||||
|
||||
Then(
|
||||
'the transaction details are presented for confirmation {string} {string} {string} {string} {string}',
|
||||
(
|
||||
receiverEmail: string,
|
||||
sendAmount: string,
|
||||
memoText: string,
|
||||
senderBalance: string,
|
||||
newSenderBalance: string,
|
||||
) => {
|
||||
cy.get('.transaction-confirm-send').contains(receiverEmail)
|
||||
cy.get('.transaction-confirm-send').contains(`+ ${sendAmount} GDD`)
|
||||
cy.get('.transaction-confirm-send').contains(memoText)
|
||||
cy.get('.transaction-confirm-send').contains(`+ ${senderBalance} GDD`)
|
||||
cy.get('.transaction-confirm-send').contains(`− ${sendAmount} GDD`)
|
||||
cy.get('.transaction-confirm-send').contains(`+ ${newSenderBalance} GDD`)
|
||||
},
|
||||
)
|
||||
|
||||
Then('the transaction details are presented for confirmation {string} {string} {string} {string} {string}', (receiverEmail: string, sendAmount: string, memoText: string, senderBalance: string, newSenderBalance: string) => {
|
||||
cy.get('.transaction-confirm-send').contains(receiverEmail)
|
||||
cy.get('.transaction-confirm-send').contains(`+ ${sendAmount} GDD`)
|
||||
cy.get('.transaction-confirm-send').contains(memoText)
|
||||
cy.get('.transaction-confirm-send').contains(`+ ${senderBalance} GDD`)
|
||||
cy.get('.transaction-confirm-send').contains(`− ${sendAmount} GDD`)
|
||||
cy.get('.transaction-confirm-send').contains(`+ ${newSenderBalance} GDD`)
|
||||
})
|
||||
|
||||
When('the user submits the transaction by confirming', (receiverName: string, amount) => {
|
||||
When('the user submits the transaction by confirming', () => {
|
||||
cy.intercept({
|
||||
method: 'POST',
|
||||
url: '/graphql',
|
||||
@ -38,11 +46,14 @@ When('the user submits the transaction by confirming', (receiverName: string, am
|
||||
|
||||
cy.wait('@sendCoins').then((interception) => {
|
||||
cy.wrap(interception.response?.statusCode).should('eq', 200)
|
||||
cy.wrap(interception.request.body)
|
||||
.should('have.property', 'query', `mutation ($identifier: String!, $amount: Decimal!, $memo: String!) {
|
||||
cy.wrap(interception.request.body).should(
|
||||
'have.property',
|
||||
'query',
|
||||
`mutation ($identifier: String!, $amount: Decimal!, $memo: String!) {
|
||||
sendCoins(identifier: $identifier, amount: $amount, memo: $memo)
|
||||
}
|
||||
` )
|
||||
`,
|
||||
)
|
||||
cy.wrap(interception.response?.body)
|
||||
.should('have.nested.property', 'data.sendCoins')
|
||||
.and('equal', true)
|
||||
@ -50,21 +61,30 @@ When('the user submits the transaction by confirming', (receiverName: string, am
|
||||
cy.get('[data-test="send-transaction-success-text"]').should('be.visible')
|
||||
})
|
||||
|
||||
Then('the {string} and {string} are displayed on the {string} page', (name: string, amount: string, page: string) => {
|
||||
switch (page) {
|
||||
case 'overview':
|
||||
cy.get('.align-items-center').contains(`${name}`)
|
||||
cy.get('.align-items-center').contains(`${amount} GDD`)
|
||||
break
|
||||
case 'send':
|
||||
cy.get('.align-items-center').contains(`${name}`)
|
||||
cy.get('.align-items-center').contains(`${amount} GDD`)
|
||||
break
|
||||
case 'transactions':
|
||||
cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('div.gdd-transaction-list-item-name', `${name}`)
|
||||
cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('[data-test="transaction-amount"]', `${amount} GDD`)
|
||||
break
|
||||
default:
|
||||
throw new Error(`Error in "Then the {string} and {string} are displayed on the {string}} page" step: incorrect page name string "${page}"`)
|
||||
}
|
||||
})
|
||||
Then(
|
||||
'the {string} and {string} are displayed on the {string} page',
|
||||
(name: string, amount: string, page: string) => {
|
||||
switch (page) {
|
||||
case 'overview':
|
||||
cy.get('.align-items-center').contains(`${name}`)
|
||||
cy.get('.align-items-center').contains(`${amount} GDD`)
|
||||
break
|
||||
case 'send':
|
||||
cy.get('.align-items-center').contains(`${name}`)
|
||||
cy.get('.align-items-center').contains(`${amount} GDD`)
|
||||
break
|
||||
case 'transactions':
|
||||
cy.get('div.mt-3 > div > div.test-list-group-item')
|
||||
.eq(0)
|
||||
.contains('div.gdd-transaction-list-item-name', `${name}`)
|
||||
cy.get('div.mt-3 > div > div.test-list-group-item')
|
||||
.eq(0)
|
||||
.contains('[data-test="transaction-amount"]', `${amount} GDD`)
|
||||
break
|
||||
default:
|
||||
throw new Error(
|
||||
`Error in "Then the {string} and {string} are displayed on the {string}} page" step: incorrect page name string "${page}"`,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@ -13,26 +13,21 @@ When('the user submits no credentials', () => {
|
||||
loginPage.submitLogin()
|
||||
})
|
||||
|
||||
When(
|
||||
'the user submits the credentials {string} {string}',
|
||||
(email: string, password: string) => {
|
||||
cy.intercept('POST', '/graphql', (req) => {
|
||||
if (
|
||||
req.body.hasOwnProperty('query') &&
|
||||
req.body.query.includes('mutation')
|
||||
) {
|
||||
req.alias = 'login'
|
||||
}
|
||||
})
|
||||
When('the user submits the credentials {string} {string}', (email: string, password: string) => {
|
||||
cy.intercept('POST', '/graphql', (req) => {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (req.body.hasOwnProperty('query') && req.body.query.includes('mutation')) {
|
||||
req.alias = 'login'
|
||||
}
|
||||
})
|
||||
|
||||
loginPage.enterEmail(email)
|
||||
loginPage.enterPassword(password)
|
||||
loginPage.submitLogin()
|
||||
cy.wait('@login').then((interception) => {
|
||||
expect(interception.response.statusCode).equals(200)
|
||||
})
|
||||
}
|
||||
)
|
||||
loginPage.enterEmail(email)
|
||||
loginPage.enterPassword(password)
|
||||
loginPage.submitLogin()
|
||||
cy.wait('@login').then((interception) => {
|
||||
expect(interception.response.statusCode).equals(200)
|
||||
})
|
||||
})
|
||||
|
||||
// password reset related
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { And, When } from '@badeball/cypress-cucumber-preprocessor'
|
||||
import { And, DataTable, When } from '@badeball/cypress-cucumber-preprocessor'
|
||||
import { ProfilePage } from '../../e2e/models/ProfilePage'
|
||||
import { Toasts } from '../../e2e/models/Toasts'
|
||||
|
||||
@ -10,8 +10,8 @@ And('the user opens the change password menu', () => {
|
||||
cy.get(profilePage.submitNewPasswordBtn).should('be.disabled')
|
||||
})
|
||||
|
||||
When('the user fills the password form with:', (table) => {
|
||||
let hashedTableRows = table.rowsHash()
|
||||
When('the user fills the password form with:', (table: DataTable) => {
|
||||
const hashedTableRows = table.rowsHash()
|
||||
profilePage.enterOldPassword(hashedTableRows['Old password'])
|
||||
profilePage.enterNewPassword(hashedTableRows['New password'])
|
||||
profilePage.enterRepeatPassword(hashedTableRows['Repeat new password'])
|
||||
@ -22,7 +22,7 @@ And('the user submits the password form', () => {
|
||||
profilePage.submitPasswordForm()
|
||||
})
|
||||
|
||||
When('the user is presented a {string} message', (type: string) => {
|
||||
When('the user is presented a {string} message', () => {
|
||||
const toast = new Toasts()
|
||||
cy.get(toast.toastSlot).within(() => {
|
||||
cy.get(toast.toastTypeSuccess)
|
||||
|
||||
@ -10,7 +10,7 @@ When(
|
||||
registrationPage.enterFirstname(firstname)
|
||||
registrationPage.enterLastname(lastname)
|
||||
registrationPage.enterEmail(email)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
And('the user agrees to the privacy policy', () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user