mirror of
https://github.com/StanGirard/quivr.git
synced 2024-11-27 10:20:32 +03:00
feat(e2e): add playright config and createBrain e2e test (#1177)
* chore: add playright config * feat: add playright first examples * feat: add 'test-e2e command' * feat: add createBrain E2E test
This commit is contained in:
parent
143d32ddf1
commit
7dd404935b
@ -6,3 +6,6 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=<change-me>
|
||||
NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY=<ignore-me-or-change-me>
|
||||
NEXT_PUBLIC_JUNE_API_KEY=<ignore-me-or-change-me>
|
||||
NEXT_PUBLIC_GROWTHBOOK_URL=<ignore-me-or-change-me>
|
||||
NEXT_PUBLIC_E2E_URL=http://localhost:3003
|
||||
NEXT_PUBLIC_E2E_EMAIL=<ignore-me-or-change-me>
|
||||
NEXT_PUBLIC_E2E_PASSWORD=<ignore-me-or-change-me>
|
3
frontend/.gitignore
vendored
3
frontend/.gitignore
vendored
@ -36,3 +36,6 @@ next-env.d.ts
|
||||
|
||||
# Sentry Auth Token
|
||||
.sentryclirc
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
|
@ -8,22 +8,24 @@ import { Divider } from "@/lib/components/ui/Divider";
|
||||
import Field from "@/lib/components/ui/Field";
|
||||
import PageHeading from "@/lib/components/ui/PageHeading";
|
||||
|
||||
import { Suspense } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { GoogleLoginButton } from "./components/GoogleLogin";
|
||||
import { MagicLinkLogin } from "./components/MagicLinkLogin";
|
||||
import { PasswordForgotten } from "./components/PasswordForgotten";
|
||||
import { useLogin } from "./hooks/useLogin";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Suspense } from "react";
|
||||
|
||||
|
||||
function Main() {
|
||||
const { handleLogin, setEmail, setPassword, email, isPending, password } =
|
||||
useLogin();
|
||||
const { t } = useTranslation(["translation","login"]);
|
||||
const { t } = useTranslation(["translation", "login"]);
|
||||
return (
|
||||
<main>
|
||||
<section className="w-full min-h-[80vh] h-full outline-none flex flex-col gap-5 items-center justify-center p-6">
|
||||
<PageHeading title={t("title",{ ns: 'login' })} subtitle={t("subtitle",{ ns: 'login' })} />
|
||||
<PageHeading
|
||||
title={t("title", { ns: "login" })}
|
||||
subtitle={t("subtitle", { ns: "login" })}
|
||||
/>
|
||||
<Card className="max-w-md w-full p-5 sm:p-10 text-left">
|
||||
<form
|
||||
data-testid="sign-in-form"
|
||||
@ -51,12 +53,16 @@ function Main() {
|
||||
/>
|
||||
|
||||
<div className="flex flex-col items-center justify-center mt-2 gap-2">
|
||||
<Button type="submit" isLoading={isPending}>
|
||||
<Button
|
||||
data-testid="submit-login"
|
||||
type="submit"
|
||||
isLoading={isPending}
|
||||
>
|
||||
{t("loginButton")}
|
||||
</Button>
|
||||
<PasswordForgotten setEmail={setEmail} email={email} />
|
||||
|
||||
<Link href="/signup">{t("signup",{ ns: 'login' })}</Link>
|
||||
<Link href="/signup">{t("signup", { ns: "login" })}</Link>
|
||||
</div>
|
||||
|
||||
<Divider text={t("or")} />
|
||||
@ -69,7 +75,7 @@ function Main() {
|
||||
</Card>
|
||||
</section>
|
||||
</main>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default function Login() {
|
||||
@ -77,6 +83,5 @@ export default function Login() {
|
||||
<Suspense fallback="Loading...">
|
||||
<Main />
|
||||
</Suspense>
|
||||
|
||||
);
|
||||
}
|
||||
|
11
frontend/e2e/index.ts
Normal file
11
frontend/e2e/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { test } from "@playwright/test";
|
||||
|
||||
import { chatTests } from "./tests/chat";
|
||||
import { createBrainTests } from "./tests/createBrain";
|
||||
import { uploadTests } from "./tests/upload";
|
||||
|
||||
test.describe(createBrainTests);
|
||||
|
||||
test.describe.skip(uploadTests);
|
||||
|
||||
test.describe.skip(chatTests);
|
13
frontend/e2e/tests/chat.ts
Normal file
13
frontend/e2e/tests/chat.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { test } from "@playwright/test";
|
||||
|
||||
import { login } from "../utils/login";
|
||||
|
||||
export const chatTests = (): void => {
|
||||
test("chat", async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto("/chat");
|
||||
await page.getByRole("combobox").locator("div").nth(2).click();
|
||||
await page.getByRole("combobox").fill("Hello");
|
||||
await page.getByTestId("submit-button").click();
|
||||
});
|
||||
};
|
13
frontend/e2e/tests/createBrain.ts
Normal file
13
frontend/e2e/tests/createBrain.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { test } from "@playwright/test";
|
||||
|
||||
import { login } from "../utils/login";
|
||||
|
||||
export const createBrainTests = (): void => {
|
||||
test("create brain", async ({ page }) => {
|
||||
await login(page);
|
||||
await page.getByTestId("brain-management-button").first().click();
|
||||
await page.getByTestId("add-brain-button").click();
|
||||
await page.getByTestId("brain-name").fill("Test brain");
|
||||
await page.getByTestId("create-brain-submit-button").click();
|
||||
});
|
||||
};
|
19
frontend/e2e/tests/upload.ts
Normal file
19
frontend/e2e/tests/upload.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { test } from "@playwright/test";
|
||||
|
||||
import { login } from "../utils/login";
|
||||
|
||||
export const uploadTests = (): void => {
|
||||
test("upload", async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto("/chat");
|
||||
await page.getByTestId("upload-button").click();
|
||||
await page
|
||||
.getByRole("button", {
|
||||
name: "Drag and drop files here, or click to browse",
|
||||
})
|
||||
.click();
|
||||
await page.getByPlaceholder("Insert website URL").click();
|
||||
await page.getByPlaceholder("Insert website URL").fill("https://quivr.app");
|
||||
await page.getByPlaceholder("Insert website URL").press("Enter");
|
||||
});
|
||||
};
|
24
frontend/e2e/utils/login.ts
Normal file
24
frontend/e2e/utils/login.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Page } from "@playwright/test";
|
||||
|
||||
export const login = async (page: Page): Promise<void> => {
|
||||
const frontendUrl = process.env.NEXT_PUBLIC_E2E_URL;
|
||||
const email = process.env.NEXT_PUBLIC_E2E_EMAIL;
|
||||
const password = process.env.NEXT_PUBLIC_E2E_PASSWORD;
|
||||
|
||||
if (frontendUrl === undefined) {
|
||||
throw new Error("NEXT_PUBLIC_E2E_URL is not defined");
|
||||
}
|
||||
if (email === undefined) {
|
||||
throw new Error("NEXT_PUBLIC_E2E_EMAIL is not defined");
|
||||
}
|
||||
if (password === undefined) {
|
||||
throw new Error("NEXT_PUBLIC_E2E_PASSWORD is not defined");
|
||||
}
|
||||
|
||||
await page.goto(frontendUrl);
|
||||
await page.getByTestId("login-button").first().click();
|
||||
await page.getByPlaceholder("Email").fill(email);
|
||||
await page.getByPlaceholder("Password").fill(password);
|
||||
await page.getByTestId("submit-login").click();
|
||||
await page.waitForURL(/chat/);
|
||||
};
|
@ -36,6 +36,7 @@ export const AddBrainModal = (): JSX.Element => {
|
||||
onClick={() => void 0}
|
||||
variant={"tertiary"}
|
||||
className="border-0"
|
||||
data-testid="add-brain-button"
|
||||
>
|
||||
{t("newBrain", { ns: "brain" })}
|
||||
<MdAdd className="text-xl" />
|
||||
@ -61,6 +62,7 @@ export const AddBrainModal = (): JSX.Element => {
|
||||
autoComplete="off"
|
||||
className="flex-1"
|
||||
required
|
||||
data-testid="brain-name"
|
||||
{...register("name")}
|
||||
/>
|
||||
|
||||
@ -152,7 +154,12 @@ export const AddBrainModal = (): JSX.Element => {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<Button isLoading={isPending} className="mt-12 self-end" type="submit">
|
||||
<Button
|
||||
isLoading={isPending}
|
||||
className="mt-12 self-end"
|
||||
type="submit"
|
||||
data-testid="create-brain-submit-button"
|
||||
>
|
||||
{t("createButton")}
|
||||
<MdAdd className="text-xl" />
|
||||
</Button>
|
||||
|
@ -7,7 +7,7 @@ import Button from "@/lib/components/ui/Button";
|
||||
export const AuthButtons = (): JSX.Element => {
|
||||
const pathname = usePathname();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const {t, i18n} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (pathname === "/signup") {
|
||||
return (
|
||||
@ -16,19 +16,19 @@ export const AuthButtons = (): JSX.Element => {
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
else if (pathname === "/login") {
|
||||
if (pathname === "/login") {
|
||||
return (
|
||||
<Link href={"/signup"}>
|
||||
<Button variant={"secondary"}>{t("signUpButton")}</Button>
|
||||
</Link>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Link href={"/login"}>
|
||||
<Button variant={"secondary"}>{t("loginButton")}</Button>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Link href={"/login"}>
|
||||
<Button data-testid="login-button" variant={"secondary"}>
|
||||
{t("loginButton")}
|
||||
</Button>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
@ -13,6 +13,7 @@ export const BrainManagementButton = (): JSX.Element => {
|
||||
variant={"tertiary"}
|
||||
className="focus:outline-none text-2xl"
|
||||
aria-label="Settings"
|
||||
data-testid="brain-management-button"
|
||||
>
|
||||
<FaBrain className="w-6 h-6" />
|
||||
</Button>
|
||||
|
@ -9,6 +9,7 @@
|
||||
"lint": "next lint",
|
||||
"lint-fix": "eslint --fix .",
|
||||
"test-unit": "vitest run",
|
||||
"test-e2e": "npx playwright test",
|
||||
"test-type": "tsc --noEmit --emitDeclarationOnly false",
|
||||
"test": "yarn test-type",
|
||||
"precommit": "yarn lint && yarn test",
|
||||
@ -78,6 +79,7 @@
|
||||
"victory": "^36.6.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.38.0",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@vitejs/plugin-react": "^4.0.1",
|
||||
@ -87,4 +89,4 @@
|
||||
"react-icons": "^4.8.0",
|
||||
"vitest": "^0.32.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
frontend/playwright.config.ts
Normal file
27
frontend/playwright.config.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { defineConfig, devices } from "@playwright/test";
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
export default defineConfig({
|
||||
testDir: "./e2e",
|
||||
fullyParallel: true,
|
||||
forbidOnly: !(process.env.CI == null),
|
||||
retries: process.env.CI != null ? 2 : 0,
|
||||
workers: 1,
|
||||
reporter: "html",
|
||||
testMatch: "e2e/index.ts",
|
||||
use: {
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
],
|
||||
webServer: {
|
||||
command:
|
||||
process.env.NODE_ENV === "production"
|
||||
? "yarn run build && yarn run start -p 3003"
|
||||
: "yarn run dev -p 3003",
|
||||
},
|
||||
});
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user