Skip to content

Commit 2eb613f

Browse files
authored
test: add type-safe navigate utility (#1032)
1 parent ec0efe5 commit 2eb613f

9 files changed

+125
-56
lines changed

tests/e2e/2fa.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import { expect, test } from '#tests/playwright-utils.ts'
44

55
test('Users can add 2FA to their account and use it when logging in', async ({
66
page,
7+
navigate,
78
login,
89
}) => {
910
const password = faker.internet.password()
1011
const user = await login({ password })
11-
await page.goto('/settings/profile')
12+
await navigate('/settings/profile')
1213

1314
await page.getByRole('link', { name: /enable 2fa/i }).click()
1415

@@ -40,7 +41,7 @@ test('Users can add 2FA to their account and use it when logging in', async ({
4041
await page.getByRole('menuitem', { name: /logout/i }).click()
4142
await expect(page).toHaveURL(`/`)
4243

43-
await page.goto('/login')
44+
await navigate('/login')
4445
await expect(page).toHaveURL(`/login`)
4546
await page.getByRole('textbox', { name: /username/i }).fill(user.username)
4647
await page.getByLabel(/^password$/i).fill(password)

tests/e2e/error-boundary.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { expect, test } from '#tests/playwright-utils.ts'
22

3-
test('Test root error boundary caught', async ({ page }) => {
3+
test('Test root error boundary caught', async ({ page, navigate }) => {
44
const pageUrl = '/does-not-exist'
5-
const res = await page.goto(pageUrl)
5+
const res = await navigate(pageUrl as any)
66

77
expect(res?.status()).toBe(404)
88
await expect(page.getByText(/We can't find this page/i)).toBeVisible()

tests/e2e/note-images.test.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import { type NoteImage, type Note } from '@prisma/client'
33
import { prisma } from '#app/utils/db.server.ts'
44
import { expect, test } from '#tests/playwright-utils.ts'
55

6-
test('Users can create note with an image', async ({ page, login }) => {
6+
test('Users can create note with an image', async ({
7+
page,
8+
navigate,
9+
login,
10+
}) => {
711
const user = await login()
8-
await page.goto(`/users/${user.username}/notes`)
12+
await navigate('/users/:username/notes', { username: user.username })
913

1014
const newNote = createNote()
1115
const altText = 'cute koala'
@@ -28,9 +32,13 @@ test('Users can create note with an image', async ({ page, login }) => {
2832
).toBeVisible()
2933
})
3034

31-
test('Users can create note with multiple images', async ({ page, login }) => {
35+
test('Users can create note with multiple images', async ({
36+
page,
37+
navigate,
38+
login,
39+
}) => {
3240
const user = await login()
33-
await page.goto(`/users/${user.username}/notes`)
41+
await navigate('/users/:username/notes', { username: user.username })
3442

3543
const newNote = createNote()
3644
const altText1 = 'cute koala'
@@ -60,7 +68,7 @@ test('Users can create note with multiple images', async ({ page, login }) => {
6068
await expect(page.getByAltText(altText2)).toBeVisible()
6169
})
6270

63-
test('Users can edit note image', async ({ page, login }) => {
71+
test('Users can edit note image', async ({ page, navigate, login }) => {
6472
const user = await login()
6573

6674
const note = await prisma.note.create({
@@ -70,7 +78,10 @@ test('Users can edit note image', async ({ page, login }) => {
7078
ownerId: user.id,
7179
},
7280
})
73-
await page.goto(`/users/${user.username}/notes/${note.id}`)
81+
await navigate('/users/:username/notes/:noteId', {
82+
username: user.username,
83+
noteId: note.id,
84+
})
7485

7586
// edit the image
7687
await page.getByRole('link', { name: 'Edit', exact: true }).click()
@@ -86,7 +97,7 @@ test('Users can edit note image', async ({ page, login }) => {
8697
await expect(page.getByAltText(updatedImage.altText)).toBeVisible()
8798
})
8899

89-
test('Users can delete note image', async ({ page, login }) => {
100+
test('Users can delete note image', async ({ page, navigate, login }) => {
90101
const user = await login()
91102

92103
const note = await prisma.note.create({
@@ -96,7 +107,10 @@ test('Users can delete note image', async ({ page, login }) => {
96107
ownerId: user.id,
97108
},
98109
})
99-
await page.goto(`/users/${user.username}/notes/${note.id}`)
110+
await navigate('/users/:username/notes/:noteId', {
111+
username: user.username,
112+
noteId: note.id,
113+
})
100114

101115
await expect(page.getByRole('heading', { name: note.title })).toBeVisible()
102116
const images = page
@@ -118,6 +132,7 @@ function createNote() {
118132
content: faker.lorem.paragraphs(3),
119133
} satisfies Omit<Note, 'id' | 'createdAt' | 'updatedAt' | 'type' | 'ownerId'>
120134
}
135+
121136
function createNoteWithImage() {
122137
return {
123138
...createNote(),

tests/e2e/notes.test.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { faker } from '@faker-js/faker'
22
import { prisma } from '#app/utils/db.server.ts'
33
import { expect, test } from '#tests/playwright-utils.ts'
44

5-
test('Users can create notes', async ({ page, login }) => {
5+
test('Users can create notes', async ({ page, navigate, login }) => {
66
const user = await login()
7-
await page.goto(`/users/${user.username}/notes`)
7+
await navigate('/users/:username/notes', { username: user.username })
88

99
const newNote = createNote()
1010
await page.getByRole('link', { name: /New Note/i }).click()
@@ -17,14 +17,17 @@ test('Users can create notes', async ({ page, login }) => {
1717
await expect(page).toHaveURL(new RegExp(`/users/${user.username}/notes/.*`))
1818
})
1919

20-
test('Users can edit notes', async ({ page, login }) => {
20+
test('Users can edit notes', async ({ page, navigate, login }) => {
2121
const user = await login()
2222

2323
const note = await prisma.note.create({
2424
select: { id: true },
2525
data: { ...createNote(), ownerId: user.id },
2626
})
27-
await page.goto(`/users/${user.username}/notes/${note.id}`)
27+
await navigate('/users/:username/notes/:noteId', {
28+
username: user.username,
29+
noteId: note.id,
30+
})
2831

2932
// edit the note
3033
await page.getByRole('link', { name: 'Edit', exact: true }).click()
@@ -41,14 +44,17 @@ test('Users can edit notes', async ({ page, login }) => {
4144
).toBeVisible()
4245
})
4346

44-
test('Users can delete notes', async ({ page, login }) => {
47+
test('Users can delete notes', async ({ page, navigate, login }) => {
4548
const user = await login()
4649

4750
const note = await prisma.note.create({
4851
select: { id: true },
4952
data: { ...createNote(), ownerId: user.id },
5053
})
51-
await page.goto(`/users/${user.username}/notes/${note.id}`)
54+
await navigate('/users/:username/notes/:noteId', {
55+
username: user.username,
56+
noteId: note.id,
57+
})
5258

5359
// find links with href prefix
5460
const noteLinks = page

tests/e2e/onboarding.test.ts

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import {
1010
USERNAME_MIN_LENGTH,
1111
} from '#app/utils/user-validation'
1212
import { readEmail } from '#tests/mocks/utils.ts'
13-
import { createUser, expect, test as base } from '#tests/playwright-utils.ts'
13+
import {
14+
createUser,
15+
expect,
16+
test as base,
17+
type AppPages,
18+
} from '#tests/playwright-utils.ts'
1419

1520
const URL_REGEX = /(?<url>https?:\/\/[^\s$.?#].[^\s]*)/
1621
const CODE_REGEX = /Here's your verification code: (?<code>[\d\w]+)/
@@ -40,10 +45,10 @@ const test = base.extend<{
4045
},
4146
})
4247

43-
test('onboarding with link', async ({ page, getOnboardingData }) => {
48+
test('onboarding with link', async ({ page, navigate, getOnboardingData }) => {
4449
const onboardingData = getOnboardingData()
4550

46-
await page.goto('/')
51+
await navigate('/')
4752

4853
await page.getByRole('link', { name: /log in/i }).click()
4954
await expect(page).toHaveURL(`/login`)
@@ -67,9 +72,9 @@ test('onboarding with link', async ({ page, getOnboardingData }) => {
6772
expect(email.to).toBe(onboardingData.email.toLowerCase())
6873
expect(email.from).toBe('[email protected]')
6974
expect(email.subject).toMatch(/welcome/i)
70-
const onboardingUrl = extractUrl(email.text)
75+
const onboardingUrl = extractUrl(email.text) as AppPages
7176
invariant(onboardingUrl, 'Onboarding URL not found')
72-
await page.goto(onboardingUrl)
77+
await navigate(onboardingUrl)
7378

7479
await expect(page).toHaveURL(/\/verify/)
7580

@@ -109,10 +114,14 @@ test('onboarding with link', async ({ page, getOnboardingData }) => {
109114
await expect(page).toHaveURL(`/`)
110115
})
111116

112-
test('onboarding with a short code', async ({ page, getOnboardingData }) => {
117+
test('onboarding with a short code', async ({
118+
page,
119+
navigate,
120+
getOnboardingData,
121+
}) => {
113122
const onboardingData = getOnboardingData()
114123

115-
await page.goto('/signup')
124+
await navigate('/signup')
116125

117126
const emailTextbox = page.getByRole('textbox', { name: /email/i })
118127
await emailTextbox.click()
@@ -137,6 +146,7 @@ test('onboarding with a short code', async ({ page, getOnboardingData }) => {
137146

138147
test('completes onboarding after GitHub OAuth given valid user details', async ({
139148
page,
149+
navigate,
140150
prepareGitHubUser,
141151
}) => {
142152
const ghUser = await prepareGitHubUser()
@@ -148,7 +158,7 @@ test('completes onboarding after GitHub OAuth given valid user details', async (
148158
}),
149159
).toBeNull()
150160

151-
await page.goto('/signup')
161+
await navigate('/signup')
152162
await page.getByRole('button', { name: /signup with github/i }).click()
153163

154164
await expect(page).toHaveURL(/\/onboarding\/github/)
@@ -186,6 +196,7 @@ test('completes onboarding after GitHub OAuth given valid user details', async (
186196

187197
test('logs user in after GitHub OAuth if they are already registered', async ({
188198
page,
199+
navigate,
189200
prepareGitHubUser,
190201
}) => {
191202
const ghUser = await prepareGitHubUser()
@@ -214,7 +225,7 @@ test('logs user in after GitHub OAuth if they are already registered', async ({
214225
})
215226
expect(connection).toBeNull()
216227

217-
await page.goto('/signup')
228+
await navigate('/signup')
218229
await page.getByRole('button', { name: /signup with github/i }).click()
219230

220231
await expect(page).toHaveURL(`/`)
@@ -235,11 +246,12 @@ test('logs user in after GitHub OAuth if they are already registered', async ({
235246

236247
test('shows help texts on entering invalid details on onboarding page after GitHub OAuth', async ({
237248
page,
249+
navigate,
238250
prepareGitHubUser,
239251
}) => {
240252
const ghUser = await prepareGitHubUser()
241253

242-
await page.goto('/signup')
254+
await navigate('/signup')
243255
await page.getByRole('button', { name: /signup with github/i }).click()
244256

245257
await expect(page).toHaveURL(/\/onboarding\/github/)
@@ -322,11 +334,11 @@ test('shows help texts on entering invalid details on onboarding page after GitH
322334
await expect(page.getByText(/thanks for signing up/i)).toBeVisible()
323335
})
324336

325-
test('login as existing user', async ({ page, insertNewUser }) => {
337+
test('login as existing user', async ({ page, navigate, insertNewUser }) => {
326338
const password = faker.internet.password()
327339
const user = await insertNewUser({ password })
328340
invariant(user.name, 'User name not found')
329-
await page.goto('/login')
341+
await navigate('/login')
330342
await page.getByRole('textbox', { name: /username/i }).fill(user.username)
331343
await page.getByLabel(/^password$/i).fill(password)
332344
await page.getByRole('button', { name: /log in/i }).click()
@@ -335,11 +347,15 @@ test('login as existing user', async ({ page, insertNewUser }) => {
335347
await expect(page.getByRole('link', { name: user.name })).toBeVisible()
336348
})
337349

338-
test('reset password with a link', async ({ page, insertNewUser }) => {
350+
test('reset password with a link', async ({
351+
page,
352+
navigate,
353+
insertNewUser,
354+
}) => {
339355
const originalPassword = faker.internet.password()
340356
const user = await insertNewUser({ password: originalPassword })
341357
invariant(user.name, 'User name not found')
342-
await page.goto('/login')
358+
await navigate('/login')
343359

344360
await page.getByRole('link', { name: /forgot password/i }).click()
345361
await expect(page).toHaveURL('/forgot-password')
@@ -356,9 +372,9 @@ test('reset password with a link', async ({ page, insertNewUser }) => {
356372
expect(email.subject).toMatch(/password reset/i)
357373
expect(email.to).toBe(user.email.toLowerCase())
358374
expect(email.from).toBe('[email protected]')
359-
const resetPasswordUrl = extractUrl(email.text)
375+
const resetPasswordUrl = extractUrl(email.text) as AppPages
360376
invariant(resetPasswordUrl, 'Reset password URL not found')
361-
await page.goto(resetPasswordUrl)
377+
await navigate(resetPasswordUrl)
362378

363379
await expect(page).toHaveURL(/\/verify/)
364380

@@ -389,9 +405,13 @@ test('reset password with a link', async ({ page, insertNewUser }) => {
389405
await expect(page.getByRole('link', { name: user.name })).toBeVisible()
390406
})
391407

392-
test('reset password with a short code', async ({ page, insertNewUser }) => {
408+
test('reset password with a short code', async ({
409+
page,
410+
navigate,
411+
insertNewUser,
412+
}) => {
393413
const user = await insertNewUser()
394-
await page.goto('/login')
414+
await navigate('/login')
395415

396416
await page.getByRole('link', { name: /forgot password/i }).click()
397417
await expect(page).toHaveURL('/forgot-password')

0 commit comments

Comments
 (0)