mirror of
https://github.com/nicotsx/zerobyte.git
synced 2026-06-02 04:58:10 -04:00
e2e: fix 2fa leakage in next tests
This commit is contained in:
@@ -576,15 +576,16 @@ test("deleting a volume cascades and removes its backup schedule", async ({ page
|
||||
await volumeLink.click();
|
||||
await expect(page).toHaveURL(/\/volumes\/[^/?#]+/);
|
||||
await expect(page.getByRole("button", { name: "Actions" })).toBeVisible();
|
||||
const deleteVolumeMenuItem = page.getByRole("menuitem", { name: "Delete" });
|
||||
|
||||
await expect(async () => {
|
||||
await page.getByRole("button", { name: "Actions" }).click();
|
||||
const deleteVolumeMenuItem = page.getByRole("menuitem", { name: "Delete" });
|
||||
await expect(deleteVolumeMenuItem).toBeVisible();
|
||||
await deleteVolumeMenuItem.click();
|
||||
await expect(page.getByRole("heading", { name: "Delete volume?" })).toBeVisible();
|
||||
}).toPass({ timeout: 10000 });
|
||||
await deleteVolumeMenuItem.click({ force: true });
|
||||
await expect(page.getByRole("heading", { name: "Delete volume?" })).toBeVisible();
|
||||
await expect(page.getByText("All backup schedules associated with this volume will also be removed.")).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("All backup schedules associated with this volume will also be removed."),
|
||||
).toBeVisible();
|
||||
await page.getByRole("button", { name: "Delete volume" }).click();
|
||||
await expect(page.getByText("Volume deleted successfully")).toBeVisible();
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ async function getRepositoryShortId(page: Page, name: string) {
|
||||
}
|
||||
|
||||
async function createRepository(page: Page, name: string) {
|
||||
await gotoAndWaitForAppReady(page, "/repositories");
|
||||
await page.getByRole("button", { name: "Create repository" }).click();
|
||||
await gotoAndWaitForAppReady(page, "/repositories/create");
|
||||
await expect(page.getByRole("textbox", { name: "Name" })).toBeVisible();
|
||||
await page.getByRole("textbox", { name: "Name" }).fill(name);
|
||||
await page.getByRole("combobox", { name: "Backend" }).click();
|
||||
await page.getByRole("option", { name: "Local" }).click();
|
||||
|
||||
@@ -1,10 +1,36 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
import type { Browser, Page } from "@playwright/test";
|
||||
import { base32 } from "@better-auth/utils/base32";
|
||||
import { createOTP } from "@better-auth/utils/otp";
|
||||
import path from "node:path";
|
||||
import { expect, test } from "./test";
|
||||
import { gotoAndWaitForAppReady } from "./helpers/page";
|
||||
|
||||
const workerPassword = "password123";
|
||||
const twoFactorPassword = "password123";
|
||||
|
||||
async function createTwoFactorUser(browser: Browser, username: string) {
|
||||
const context = await browser.newContext({
|
||||
baseURL: `http://${process.env.SERVER_IP}:4096`,
|
||||
storageState: { cookies: [], origins: [] },
|
||||
});
|
||||
const page = await context.newPage();
|
||||
|
||||
await gotoAndWaitForAppReady(page, "/onboarding");
|
||||
await page.getByRole("textbox", { name: "Email" }).fill(`${username}@example.com`);
|
||||
await page.getByRole("textbox", { name: "Username" }).fill(username);
|
||||
await page.getByRole("textbox", { name: "Password", exact: true }).fill(twoFactorPassword);
|
||||
await page.getByRole("textbox", { name: "Confirm Password" }).fill(twoFactorPassword);
|
||||
await page.getByRole("button", { name: "Create admin user" }).click();
|
||||
await expect(page.getByText("Download Your Recovery Key")).toBeVisible();
|
||||
|
||||
await page.getByRole("textbox", { name: "Confirm Your Password" }).fill(twoFactorPassword);
|
||||
const downloadPromise = page.waitForEvent("download");
|
||||
await page.getByRole("button", { name: "Download Recovery Key" }).click();
|
||||
const download = await downloadPromise;
|
||||
await download.saveAs(path.join(process.cwd(), "playwright", `restic-${username}.pass`));
|
||||
await expect(page).toHaveURL("/volumes");
|
||||
|
||||
return { context, page };
|
||||
}
|
||||
|
||||
async function generateTotp(secret: string) {
|
||||
const decodedSecret = new TextDecoder().decode(base32.decode(secret));
|
||||
@@ -16,36 +42,43 @@ async function fillOtp(page: Page, code: string) {
|
||||
await page.keyboard.type(code);
|
||||
}
|
||||
|
||||
test("user can enable 2FA and sign in with a TOTP code", async ({ page }) => {
|
||||
await gotoAndWaitForAppReady(page, "/settings");
|
||||
test("user can enable 2FA and sign in with a TOTP code", async ({ browser }, testInfo) => {
|
||||
const username = `e2e-2fa-${testInfo.parallelIndex}-${testInfo.retry}`;
|
||||
const { context, page: twoFactorPage } = await createTwoFactorUser(browser, username);
|
||||
|
||||
const username = await page.locator("#username").inputValue();
|
||||
try {
|
||||
await gotoAndWaitForAppReady(twoFactorPage, "/settings");
|
||||
|
||||
await page.getByRole("button", { name: "Enable 2FA" }).click();
|
||||
await page.getByRole("textbox", { name: "Password" }).fill(workerPassword);
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
await twoFactorPage.getByRole("button", { name: "Enable 2FA" }).click();
|
||||
await twoFactorPage.getByRole("textbox", { name: "Password" }).fill(twoFactorPassword);
|
||||
await twoFactorPage.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
await expect(page.getByRole("heading", { name: "Scan QR Code" })).toBeVisible();
|
||||
const secret = await page.locator("input[readonly]").inputValue();
|
||||
await expect(twoFactorPage.getByRole("heading", { name: "Scan QR Code" })).toBeVisible();
|
||||
const secret = await twoFactorPage.locator("input[readonly]").inputValue();
|
||||
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Verify setup" })).toBeVisible();
|
||||
await twoFactorPage.getByRole("button", { name: "Continue" }).click();
|
||||
await expect(twoFactorPage.getByRole("heading", { name: "Verify setup" })).toBeVisible();
|
||||
|
||||
await fillOtp(page, await generateTotp(secret));
|
||||
await fillOtp(twoFactorPage, await generateTotp(secret));
|
||||
|
||||
await expect(page.getByText(/Status:\s*Enabled/)).toBeVisible();
|
||||
await expect(twoFactorPage.getByText(/Status:\s*Enabled/)).toBeVisible();
|
||||
|
||||
await page.context().clearCookies();
|
||||
await gotoAndWaitForAppReady(page, "/login");
|
||||
await context.clearCookies();
|
||||
await gotoAndWaitForAppReady(twoFactorPage, "/login");
|
||||
|
||||
await page.getByRole("textbox", { name: "Username" }).fill(username);
|
||||
await page.getByRole("textbox", { name: "Password" }).fill(workerPassword);
|
||||
await page.getByRole("button", { name: "Login" }).click();
|
||||
const usernameInput = twoFactorPage.getByRole("textbox", { name: "Username" });
|
||||
await usernameInput.fill(username);
|
||||
await expect(usernameInput).toHaveValue(username);
|
||||
await twoFactorPage.getByRole("textbox", { name: "Password" }).fill(twoFactorPassword);
|
||||
await twoFactorPage.getByRole("button", { name: "Login" }).click();
|
||||
|
||||
await expect(page.getByRole("heading", { name: "Two-Factor Authentication" })).toBeVisible();
|
||||
await expect(twoFactorPage.getByRole("heading", { name: "Two-Factor Authentication" })).toBeVisible();
|
||||
|
||||
await fillOtp(page, await generateTotp(secret));
|
||||
await fillOtp(twoFactorPage, await generateTotp(secret));
|
||||
|
||||
await expect(page).toHaveURL("/volumes");
|
||||
await expect(page.getByRole("button", { name: "Create Volume" })).toBeVisible();
|
||||
await expect(twoFactorPage).toHaveURL("/volumes");
|
||||
await expect(twoFactorPage.getByRole("button", { name: "Create Volume" })).toBeVisible();
|
||||
} finally {
|
||||
await context.close();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user