51 lines
1.9 KiB
TypeScript
51 lines
1.9 KiB
TypeScript
import type { Page } from "@playwright/test";
|
|
import { base32 } from "@better-auth/utils/base32";
|
|
import { createOTP } from "@better-auth/utils/otp";
|
|
import { expect, test } from "./test";
|
|
import { gotoAndWaitForAppReady } from "./helpers/page";
|
|
|
|
const workerPassword = "password123";
|
|
|
|
async function generateTotp(secret: string) {
|
|
const decodedSecret = new TextDecoder().decode(base32.decode(secret));
|
|
return createOTP(decodedSecret).totp();
|
|
}
|
|
|
|
async function fillOtp(page: Page, code: string) {
|
|
await page.locator('[data-slot="input-otp"]').click();
|
|
await page.keyboard.type(code);
|
|
}
|
|
|
|
test("user can enable 2FA and sign in with a TOTP code", async ({ page }) => {
|
|
await gotoAndWaitForAppReady(page, "/settings");
|
|
|
|
const username = await page.locator("#username").inputValue();
|
|
|
|
await page.getByRole("button", { name: "Enable 2FA" }).click();
|
|
await page.getByRole("textbox", { name: "Password" }).fill(workerPassword);
|
|
await page.getByRole("button", { name: "Continue" }).click();
|
|
|
|
await expect(page.getByRole("heading", { name: "Scan QR Code" })).toBeVisible();
|
|
const secret = await page.locator("input[readonly]").inputValue();
|
|
|
|
await page.getByRole("button", { name: "Continue" }).click();
|
|
await expect(page.getByRole("heading", { name: "Verify setup" })).toBeVisible();
|
|
|
|
await fillOtp(page, await generateTotp(secret));
|
|
|
|
await expect(page.getByText(/Status:\s*Enabled/)).toBeVisible();
|
|
|
|
await page.context().clearCookies();
|
|
await gotoAndWaitForAppReady(page, "/login");
|
|
|
|
await page.getByRole("textbox", { name: "Username" }).fill(username);
|
|
await page.getByRole("textbox", { name: "Password" }).fill(workerPassword);
|
|
await page.getByRole("button", { name: "Login" }).click();
|
|
|
|
await expect(page.getByRole("heading", { name: "Two-Factor Authentication" })).toBeVisible();
|
|
|
|
await fillOtp(page, await generateTotp(secret));
|
|
|
|
await expect(page).toHaveURL("/volumes");
|
|
await expect(page.getByRole("heading", { name: "No volume" })).toBeVisible();
|
|
});
|