Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 13 additions & 18 deletions frontend/tests/reset-password.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { expect, test } from "@playwright/test"
import { emailUrl, findLastEmail } from "./utils/mailpit"
import { waitForEmailHtml } from "./utils/mailpit"
import { randomEmail, randomPassword } from "./utils/random"
import { logInUser, signUpNewUser } from "./utils/user"

test.use({ storageState: { cookies: [], origins: [] } })

const resetPath = "/reset-password?token="

test("Password Recovery title is visible", async ({ page }) => {
await page.goto("/recover-password")

Expand Down Expand Up @@ -44,21 +46,17 @@ test("User can reset password successfully using the link", async ({

await page.getByRole("button", { name: "Continue" }).click()

const emailData = await findLastEmail({
const emailHtml = await waitForEmailHtml({
request,
query: `to:${email}`,
timeout: 5000,
})

await page.goto(emailUrl(emailData))

const selector = 'a[href*="/reset-password?token="]'

const url = await page.getAttribute(selector, "href")
const resetUrl = new URL(url!)
expect(emailHtml).toContain(resetPath)
const resetUrl = emailHtml.match(/\/reset-password\?token=[^"]+/)?.[0]
expect(resetUrl).toBeDefined()

// Set the new password and confirm it
await page.goto(`${resetUrl.pathname}${resetUrl.search}`)
await page.goto(resetUrl!)

await page.getByTestId("new-password-input").fill(newPassword)
await page.getByTestId("confirm-password-input").fill(newPassword)
Expand Down Expand Up @@ -95,20 +93,17 @@ test("Weak new password validation", async ({ page, request }) => {
await page.getByTestId("email-input").fill(email)
await page.getByRole("button", { name: "Continue" }).click()

const emailData = await findLastEmail({
const emailHtml = await waitForEmailHtml({
request,
query: `to:${email}`,
timeout: 5000,
})

await page.goto(emailUrl(emailData))

const selector = 'a[href*="/reset-password?token="]'
const url = await page.getAttribute(selector, "href")
const resetUrl = new URL(url!)
expect(emailHtml).toContain(resetPath)
const resetUrl = emailHtml.match(/\/reset-password\?token=[^"]+/)?.[0]
expect(resetUrl).toBeDefined()

// Set a weak new password
await page.goto(`${resetUrl.pathname}${resetUrl.search}`)
await page.goto(resetUrl!)
await page.getByTestId("new-password-input").fill(weakPassword)
await page.getByTestId("confirm-password-input").fill(weakPassword)
await page.getByRole("button", { name: "Reset Password" }).click()
Expand Down
55 changes: 21 additions & 34 deletions frontend/tests/utils/mailpit.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,10 @@
import type { APIRequestContext } from "@playwright/test"

type Address = {
Name: string
Address: string
}

type Email = {
type EmailSummary = {
ID: string
To: Address[]
Subject: string
}

async function findEmail({
request,
query,
}: {
request: APIRequestContext
query: string
}) {
const response = await request.get(
`${process.env.MAILPIT_HOST}/api/v1/search`,
{
params: { query, limit: 1 },
},
)

const { messages }: { messages: Email[] } = await response.json()

return messages[0] ?? null
}

export async function findLastEmail({
export async function waitForEmailHtml({
request,
query,
timeout = 5000,
Expand All @@ -42,18 +16,31 @@ export async function findLastEmail({
const deadline = Date.now() + timeout

while (Date.now() < deadline) {
const email = await findEmail({ request, query })
const response = await request.get(
`${process.env.MAILPIT_HOST}/api/v1/search`,
{
params: { query, limit: 1 },
},
)
const { messages }: { messages: EmailSummary[] } = await response.json()
const email = messages[0]

if (email) {
return email
const htmlResponse = await request.get(
`${process.env.MAILPIT_HOST}/view/${email.ID}.html`,
)

if (!htmlResponse.ok()) {
throw new Error(
`Could not get the HTML for email "${email.ID}": ${htmlResponse.status()}`,
)
}

return htmlResponse.text()
}

await new Promise((resolve) => setTimeout(resolve, 100))
}

throw new Error(`Timeout while trying to get the latest email for "${query}"`)
}

export function emailUrl(email: Email) {
return `${process.env.MAILPIT_HOST}/view/${email.ID}.html`
}