Skip to content

Commit

Permalink
e2e: campaign application admin and giver specs
Browse files Browse the repository at this point in the history
- add logic for admin or giver user login (see fixtures.ts)
- add logic to get a localized text for the e2e tests
- test edit a campaign application from admin UI
- test create a campaign application from general user UI
  • Loading branch information
gparlakov committed Oct 5, 2024
1 parent da8aa1e commit 073e1a3
Show file tree
Hide file tree
Showing 9 changed files with 423 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import {
CampaignApplicationResponse,
CampaignApplicationExisting,
CampaignApplicationAdminResponse,
} from '../../../../src/gql/campaign-applications'
import { Page } from 'playwright/test'
import { expect, adminTest as test } from '../../../utils/fixtures'
import { textLocalized } from '../../../utils/texts-localized'

test.describe('Campaign application admin', () => {
test('should see list of applications', async ({ page, baseURL }) => {
// arrange
const { paginationFooter } = await setup(page)
.withCampaignApplications([
{ id: '1', state: 'review' },
{ id: '2', state: 'approved' },
{ id: '3', state: 'denied' },
{ id: '4', state: 'forCommitteeReview' },
{ id: '5' },
])
.build()

// act
await page.goto(`${baseURL}/admin/campaign-applications`)

// assert
const t = await textLocalized().campaign.bg()
await expect(page.getByRole('heading')).toHaveText(t.admin.title)
await expect(page.getByRole('row')).toHaveCount(6) // title + 5 campaigns
await expect(page.getByRole('row').nth(1)).toContainText(t.status.review)
await expect(page.getByRole('row').nth(2)).toContainText(t.status.approved)
await expect(page.getByRole('row').nth(3)).toContainText(t.status.denied)
await expect(page.getByRole('row').nth(4)).toContainText(t.status.forCommitteeReview)
await expect(page.getByRole('row').nth(5)).toContainText(t.status.requestInfo)
await expect(paginationFooter(page)).toHaveText('Rows per page:1001–5 of 5')
})

test('should open a campaign application for edit', async ({ page, baseURL }) => {
// arrange
await setup(page).withEditCampaignApplication({}).build()

// act
await page.goto(`${baseURL}/admin/campaign-applications/edit/1234`)

// assert
const t = await textLocalized().campaign.bg()
await expect(page.getByRole('heading').first()).toHaveText(t.admin.title)
await expect(page.getByRole('heading').nth(1)).toHaveText(t.steps.admin.title)
})

test('should update status of campaign application to approved, archive it, and set the external link', async ({
page,
baseURL,
}) => {
// arrange
await setup(page).withEditCampaignApplication({ id: '1234', state: 'review' }).build()
await page.goto(`${baseURL}/admin/campaign-applications/edit/1234`)
const t = await textLocalized().campaign.bg()

// act
await page.getByLabel(t.steps.admin.status).click()
await page.getByText(t.status.approved).click()

const [req] = await Promise.all([
page.waitForRequest(/campaign-application\/1234/),
page.getByRole('button', { name: t.result.editButton }).click(),
])

// assert
const postData = req.postDataJSON()
expect(postData.state).toEqual('approved')
expect(page.getByText(t.result.edited)).toBeInViewport()
})
})

function setup(page: Page) {
const promises: Promise<unknown>[] = []

const builder = {
withCampaignApplications(cams: Array<Partial<CampaignApplicationResponse>>) {
promises.push(
page.route('*/**/api/v1/campaign-application/list', (route, req) => {
return route.fulfill({
json: cams.map((c) => ({ ...defaultCampaignApplication(), ...c })),
})
}),
)
return builder
},

withEditCampaignApplication(c: Partial<CampaignApplicationExisting>) {
promises.push(
page.route('*/**/api/v1/campaign-application/byId/*', (route, req) => {
return route.fulfill({
json: { ...camAppForEdit(), ...c },
})
}),
page.route(`*/**/api/v1/campaign-application/${c.id}`, (r) => {
return r.fulfill({ json: { ...camAppForEdit(), ...c } })
}),
)
return builder
},

async build() {
await promises

const selectors = {
paginationFooter: (p: Page) => p.locator('.MuiDataGrid-footerContainer'),
}

return selectors
},
}

return builder
}

function defaultCampaignApplication(): CampaignApplicationAdminResponse {
return {
id: 'eb4347a2-c8b4-47f1-83e5-67457b20909c',
createdAt: '2024-09-13T09:26:50.909Z',
updatedAt: '2024-09-28T20:56:13.728Z',
organizerName: 'Giver Dev',
organizerEmail: '[email protected]',
organizerPhone: '+35928700500',
beneficiary: 'Bene',
organizerBeneficiaryRel: 'бене',
campaignName: 'Camp name',
goal: 'Целта на кампанията',
history: '',
amount: '1455',
description: '',
state: 'requestInfo',
campaignTypeId: 'c6ef0a79-11cf-4175-9f66-3cec940c9259',
ticketURL: 'https://trello.com/linkforthiscamapp',
archived: false,
campaignEnd: 'date',
campaignEndDate: '2025-09-30T00:00:00.000Z',
acceptTermsAndConditions: true,
transparencyTermsAccepted: true,
personalInformationProcessingAccepted: true,
}
}

function camAppForEdit(): CampaignApplicationExisting {
return {
id: 'eb4347a2-c8b4-47f1-83e5-67457b20909c',
organizerName: 'Giver Dev',
organizerEmail: '[email protected]',
organizerPhone: '+35928700500',
beneficiary: 'Bene',
organizerBeneficiaryRel: 'бене',
campaignName: 'Camp name',
goal: 'Целта на кампанията',
history: '',
amount: '1455',
description: '',
state: 'requestInfo',
campaignTypeId: 'c6ef0a79-11cf-4175-9f66-3cec940c9259',
ticketURL: 'https://trello.com/linkforthiscamapp',
archived: false,
campaignEnd: 'date',
campaignEndDate: '2025-09-30T00:00:00.000Z',
acceptTermsAndConditions: true,
transparencyTermsAccepted: true,
personalInformationProcessingAccepted: true,
documents: [],
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import {
CampaignApplicationResponse,
CampaignApplicationExisting,
CampaignApplicationAdminResponse,
} from '../../../../src/gql/campaign-applications'
import { Page } from 'playwright/test'
import { expect, giverTest as test } from '../../../utils/fixtures'
import { textLocalized } from '../../../utils/texts-localized'

test.describe('Campaign application giver', () => {
test('should see the first step - organizer - of create campaign application wizard and after accepting the terms to be able to go to step 2', async ({
page,
baseURL,
}) => {
// arrange
// act
await page.goto(`${baseURL}/campaigns/application`)

// assert
const t = await textLocalized().campaign.bg()
await expect(page.getByRole('heading')).toHaveText(t.steps.organizer.title)

await page.getByRole('checkbox').first().click()
await page.getByRole('checkbox').nth(1).click()
await page.getByRole('checkbox').nth(2).click()

await page.getByRole('button', { name: t.cta.next }).click()

// assert
await expect(page.getByRole('heading')).toHaveText(t.steps.application.title)
})

test('should see the second step -application - of create campaign application wizard and after filling in the beneficiary, relations, title, type and funds go to step 3', async ({
page,
baseURL,
}) => {
// arrange
await page.goto(`${baseURL}/campaigns/application`)
const t = await textLocalized().campaign.bg()

// step 1
await page.getByRole('checkbox').first().click()
await page.getByRole('checkbox').nth(1).click()
await page.getByRole('checkbox').nth(2).click()
await page.getByRole('button', { name: t.cta.next }).click()

// act
await page.getByLabel(t.steps.application.beneficiary).fill('beneficiary')
await page.getByLabel(t.steps.application.beneficiaryRelationship).fill('rel')
await page.getByLabel(t.steps.application.campaignTitle).fill('title')

// select type of campaign app by opening the dropdown and arrow down and enter to select
await page.locator('[name="applicationBasic.campaignType"]').click({ force: true }) // this is the underlying input and it's hidden - hence the force
await page.keyboard.down('ArrowDown')
await page.keyboard.down('Enter')

await page.getByLabel(t.steps.application.funds).fill('12345')

// go next
await page.getByRole('button', { name: t.cta.next }).click()

// assert
await expect(page.getByRole('heading')).toHaveText(t.steps.details.title)
})

test('should see the third step - details - of create campaign application wizard and after filling the title, description, history and 2 files be able to create a new campaign application', async ({
page,
baseURL,
}) => {
// arrange
await page.goto(`${baseURL}/campaigns/application`)
const t = await textLocalized().campaign.bg()

// step 1
await page.getByRole('checkbox').first().click()
await page.getByRole('checkbox').nth(1).click()
await page.getByRole('checkbox').nth(2).click()
await page.getByRole('button', { name: t.cta.next }).click()
// step 2
await page.getByLabel(t.steps.application.beneficiary).fill('beneficiary')
await page.getByLabel(t.steps.application.beneficiaryRelationship).fill('rel')
await page.getByLabel(t.steps.application.campaignTitle).fill('title')

// select type of campaign app by opening the dropdown and arrow down and enter to select
await page.locator('[name="applicationBasic.campaignType"]').click({ force: true }) // this is the underlying input and it's hidden - hence the force
await page.keyboard.down('ArrowDown')
await page.keyboard.down('Enter')

await page.getByLabel(t.steps.application.funds).fill('12345')

await page.getByRole('button', { name: t.cta.next }).click()

// act
await page.getByLabel(t.steps.details.cause).fill('goal')
await page.getByLabel(t.steps.details.description).fill('description')
await page.getByLabel(t.steps.details['current-status'].label).fill('history')

await page.getByLabel(t.steps.details.documents).setInputFiles([
{
name: 'file.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test'),
},
{
name: 'file1.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test'),
},
])

// ensure we intercept the create and not let it go to the server...
page.route('*/**/api/v1/campaign-application/create', (route, req) => {
return route.fulfill({
json: defaultCampaignApplication(),
})
})
// and the upload file as well
page.route('*/**/api/v1/campaign-application/uploadFile/*', (route, req) => {
return route.fulfill({
json: { id: '1' },
})
})

const [createApplication, uploadFile1, uploadFile2] = await Promise.all([
page.waitForRequest(/\/api\/v1\/campaign-application\/create/),
page.waitForRequest(/\/api\/v1\/campaign-application\/uploadFile.*/),
page.waitForRequest(/\/api\/v1\/campaign-application\/uploadFile.*/),
page.getByRole('button', { name: t.cta.submit }).click(),
])

// assert
await expect(createApplication.postDataJSON()).toEqual({
acceptTermsAndConditions: true,
amount: '12345',
archived: false,
beneficiary: 'beneficiary',
campaignEnd: 'funds',
campaignName: 'title',
campaignTypeId: 'b9043466-a3c1-4ced-b951-6282ca3e6a7b',
description: 'description',
goal: 'goal',
history: 'history',
organizerBeneficiaryRel: 'rel',
organizerEmail: '[email protected]',
organizerName: 'Giver Dev',
organizerPhone: '+35928700500',
personalInformationProcessingAccepted: true,
state: 'review',
ticketURL: '',
transparencyTermsAccepted: true,
})

expect(uploadFile1.method()).toEqual('POST')
expect(uploadFile1.url()).toMatch('api/v1/campaign-application/uploadFile/created')
expect(uploadFile2.method()).toEqual('POST')
expect(uploadFile2.url()).toMatch('api/v1/campaign-application/uploadFile/created')

await expect(page.getByRole('heading')).toHaveText(t.result.created)
await expect(page.getByText('file.txt')).toBeVisible()
await expect(page.getByText('file1.txt')).toBeVisible()
await expect(page.getByText('[email protected]')).toBeVisible()
await expect(page.getByText('Giver Dev')).toBeVisible()
await expect(page.getByText('+35928700500')).toBeVisible()
await expect(page.getByText('beneficiary')).toBeVisible()
await expect(page.getByText('rel')).toBeVisible()
await expect(page.getByText('title')).toBeVisible()
await expect(page.getByText('12345')).toBeVisible()
await expect(page.getByText(t.steps.application['campaign-end'].options.funds)).toBeVisible()
await expect(page.getByText('goal')).toBeVisible()
})
})

function defaultCampaignApplication() {
return {
id: 'created',
acceptTermsAndConditions: true,
personalInformationProcessingAccepted: true,
transparencyTermsAccepted: true,
organizerName: 'Giver Dev',
organizerEmail: '[email protected]',
organizerPhone: '+35928700500',
beneficiary: 'beneficiary',
campaignName: 'title',
amount: '12345',
goal: 'goal',
description: '',
organizerBeneficiaryRel: 'rel',
history: '',
campaignEnd: 'funds',
campaignTypeId: 'b9043466-a3c1-4ced-b951-6282ca3e6a7b',
archived: false,
state: 'review',
ticketURL: '',
}
}
11 changes: 11 additions & 0 deletions e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "..",
"paths": {
"@src/*": ["./src/*"]
}
},
"include": ["./e2e", "./src"],
"exclude": ["./node_modules"]
}
Loading

0 comments on commit 073e1a3

Please sign in to comment.