Skip to content

Commit dafbe5f

Browse files
committed
test: add transaction payment e2e coverage
1 parent 8501a5a commit dafbe5f

1 file changed

Lines changed: 161 additions & 0 deletions

File tree

e2e/transaction-flows.spec.ts

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import { Course, PrismaClient, Transaction, User } from '@prisma/client'
2+
import { readFixture } from '../app/utils/fixtures'
3+
import { generateId } from '../app/utils/nanoid'
4+
import { stripLeadingPlus } from '../app/utils/misc'
5+
import { getWhatsAppLinkForConfirmation } from '../app/utils/whatsapp'
6+
import { transactionBuilder } from '../app/models/__mocks__/transaction'
7+
import { userBuilder } from '../app/models/__mocks__/user'
8+
import { test, expect } from './base-test'
9+
import { authFixtures, getDataFixturePath, isStagingEnv } from './fixtures'
10+
11+
process.env.DATABASE_URL = process.env.DATABASE_URL ?? 'file:./test.db'
12+
13+
const db = new PrismaClient()
14+
15+
test.skip(isStagingEnv, 'Skipping on staging - creates local transaction data')
16+
test.skip(
17+
({ browserName, noscript }) => browserName !== 'chromium' || noscript,
18+
'Transaction flow tests mutate shared local database fixtures'
19+
)
20+
21+
test.afterAll(async () => {
22+
await db.$disconnect()
23+
})
24+
25+
async function readUserFixture(name: string): Promise<User> {
26+
return JSON.parse(await readFixture(getDataFixturePath('users', name)))
27+
}
28+
29+
async function getCourse(): Promise<Course> {
30+
const course = await db.course.findFirst()
31+
32+
if (!course) {
33+
throw new Error('Expected a seeded course fixture')
34+
}
35+
36+
return course
37+
}
38+
39+
test.describe('Transaction confirmation process', () => {
40+
test.use({ storageState: authFixtures.memberEdit })
41+
42+
test.beforeEach(async () => {
43+
const member = await readUserFixture('member-edit')
44+
await db.transaction.deleteMany({ where: { userId: member.id } })
45+
})
46+
47+
test('submits payment details and generates the WhatsApp confirmation link', async ({
48+
page,
49+
baseURL,
50+
}) => {
51+
const author = await readUserFixture('author')
52+
53+
await page.goto('/dashboard/purchase/confirm')
54+
55+
await page.getByRole('textbox', { name: /nama bank/i }).fill('Bank Jago')
56+
await page
57+
.getByRole('textbox', { name: /nomor rekening/i })
58+
.fill('123-456-789')
59+
await page
60+
.getByRole('textbox', { name: /nama pemilik rekening/i })
61+
.fill('Member Edit')
62+
await page.getByRole('textbox', { name: /nominal/i }).fill('200000')
63+
64+
await page.getByRole('button', { name: /konfirmasi pembayaran/i }).click()
65+
await page.waitForURL(/\/dashboard\/purchase\/verify\/[^/]+$/)
66+
67+
const verifyPurchaseLink = page.getByRole('link', {
68+
name: /verifikasi pembelian/i,
69+
})
70+
await expect(verifyPurchaseLink).toBeVisible()
71+
72+
await expect(verifyPurchaseLink).toHaveAttribute(
73+
'href',
74+
/\/dashboard\/purchase\/verify\/[^/]+$/
75+
)
76+
77+
const verifyPurchaseHref = await verifyPurchaseLink.getAttribute('href')
78+
const transactionId = (verifyPurchaseHref as string).split('/').at(-1)
79+
const href = getWhatsAppLinkForConfirmation(
80+
author.phoneNumber,
81+
transactionId as string,
82+
baseURL
83+
)
84+
85+
const url = new URL(href)
86+
expect(url.origin).toBe('https://api.whatsapp.com')
87+
expect(url.pathname).toBe('/send')
88+
expect(url.searchParams.get('phone')).toBe(
89+
stripLeadingPlus(author.phoneNumber)
90+
)
91+
expect(url.searchParams.get('text')).toContain(
92+
`${baseURL}/dashboard/transactions/${transactionId}`
93+
)
94+
})
95+
})
96+
97+
test.describe('Transaction verification process', () => {
98+
test.use({ storageState: authFixtures.author })
99+
100+
let member: User
101+
let transaction: Transaction
102+
103+
test.beforeEach(async () => {
104+
const course = await getCourse()
105+
member = await db.user.create({
106+
data: {
107+
id: generateId(),
108+
...userBuilder({ overrides: { phoneNumber: '+6281234567890' } }),
109+
},
110+
})
111+
transaction = await db.transaction.create({
112+
data: {
113+
id: generateId(),
114+
userId: member.id,
115+
courseId: course.id,
116+
authorId: course.authorId,
117+
...transactionBuilder(),
118+
},
119+
})
120+
})
121+
122+
test('verifies a submitted transaction and exposes the member WhatsApp link', async ({
123+
page,
124+
}) => {
125+
await page.goto(`/dashboard/transactions/${transaction.id}`)
126+
127+
const contactWhatsAppButton = page.getByRole('link', {
128+
name: /kontak whatsapp/i,
129+
})
130+
await expect(contactWhatsAppButton).toBeVisible()
131+
await expect(contactWhatsAppButton).toHaveAttribute(
132+
'href',
133+
`https://wa.me/${stripLeadingPlus(member.phoneNumber)}`
134+
)
135+
136+
const verifyTransactionLink = page.getByRole('link', {
137+
name: /verifikasi transaksi/i,
138+
})
139+
await expect(verifyTransactionLink).toHaveAttribute(
140+
'href',
141+
`/dashboard/transactions/${transaction.id}/verify`
142+
)
143+
144+
const response = await page.request.post(
145+
`/dashboard/transactions/${transaction.id}/verify`,
146+
{
147+
form: {
148+
status: 'VERIFIED',
149+
notes: 'Valid payment',
150+
},
151+
}
152+
)
153+
expect(response.ok()).toBe(true)
154+
155+
await page.goto(`/dashboard/transactions/${transaction.id}`)
156+
await expect(page.locator('id=transaction-status')).toContainText(
157+
'Terverifikasi'
158+
)
159+
await expect(page.locator('id=notes')).toContainText('Valid payment')
160+
})
161+
})

0 commit comments

Comments
 (0)