diff --git a/packages/web/.gitignore b/packages/web/.gitignore new file mode 100644 index 0000000..aaa9103 --- /dev/null +++ b/packages/web/.gitignore @@ -0,0 +1,2 @@ +test-results/ +playwright-report/ diff --git a/packages/web/e2e/sidebar.spec.ts b/packages/web/e2e/sidebar.spec.ts new file mode 100644 index 0000000..b0eb6e0 --- /dev/null +++ b/packages/web/e2e/sidebar.spec.ts @@ -0,0 +1,29 @@ +import { expect, test } from "@playwright/test"; + +const CONFIG_KEY = "openconcho:config"; +const CONFIG_VALUE = JSON.stringify({ baseUrl: "http://localhost:9999", token: "" }); + +test.describe("Sidebar", () => { + test.beforeEach(async ({ context }) => { + await context.addInitScript( + ([key, value]) => { + window.localStorage.setItem(key, value); + }, + [CONFIG_KEY, CONFIG_VALUE], + ); + }); + + test("renders the sidebar nav on the dashboard route", async ({ page }) => { + await page.goto("/"); + await expect(page.getByRole("complementary")).toBeVisible(); + await expect(page.getByRole("link", { name: /dashboard/i })).toBeVisible(); + await expect(page.getByRole("link", { name: /workspaces/i })).toBeVisible(); + await expect(page.getByRole("link", { name: /settings/i })).toBeVisible(); + }); + + test("renders the sidebar nav on the settings route", async ({ page }) => { + await page.goto("/settings"); + await expect(page.getByRole("complementary")).toBeVisible(); + await expect(page.getByRole("link", { name: /dashboard/i })).toBeVisible(); + }); +}); diff --git a/packages/web/package.json b/packages/web/package.json index a56bdea..00056b4 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -10,12 +10,10 @@ "lint": "biome check src/", "lint:fix": "biome check --write src/", "test": "vitest run --passWithNoTests", + "test:e2e": "playwright test", "generate:api": "openapi-typescript openapi.json -o src/api/schema.d.ts" }, "dependencies": { - "@tauri-apps/api": "^2", - "@tauri-apps/plugin-http": "^2", - "@tauri-apps/plugin-shell": "^2", "@fontsource/dm-mono": "^5.2.7", "@fontsource/dm-sans": "^5.2.8", "@radix-ui/react-collapsible": "^1.1.12", @@ -27,6 +25,9 @@ "@tailwindcss/vite": "^4.2.4", "@tanstack/react-query": "^5.74.4", "@tanstack/react-router": "^1.120.3", + "@tauri-apps/api": "^2", + "@tauri-apps/plugin-http": "^2", + "@tauri-apps/plugin-shell": "^2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "framer-motion": "^12.38.0", @@ -42,6 +43,7 @@ "zod": "catalog:" }, "devDependencies": { + "@playwright/test": "^1.59.1", "@tanstack/router-plugin": "^1.120.3", "@testing-library/jest-dom": "catalog:", "@testing-library/react": "catalog:", diff --git a/packages/web/playwright.config.ts b/packages/web/playwright.config.ts new file mode 100644 index 0000000..350ca99 --- /dev/null +++ b/packages/web/playwright.config.ts @@ -0,0 +1,17 @@ +import { defineConfig, devices } from "@playwright/test"; + +export default defineConfig({ + testDir: "./e2e", + fullyParallel: true, + reporter: "list", + use: { + baseURL: "http://localhost:5173", + }, + projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }], + webServer: { + command: "pnpm dev", + url: "http://localhost:5173", + reuseExistingServer: !process.env.CI, + timeout: 60_000, + }, +}); diff --git a/packages/web/src/routes/__root.tsx b/packages/web/src/routes/__root.tsx index 07b902f..8dce51e 100644 --- a/packages/web/src/routes/__root.tsx +++ b/packages/web/src/routes/__root.tsx @@ -1,4 +1,4 @@ -import { createRootRoute, Outlet, redirect, useRouter } from "@tanstack/react-router"; +import { createRootRoute, Outlet, redirect } from "@tanstack/react-router"; import { useEffect } from "react"; import { Sidebar } from "@/components/layout/Sidebar"; import { loadConfig } from "@/lib/config"; @@ -7,17 +7,10 @@ import { applyTheme, getStoredTheme } from "@/lib/theme"; const SETTINGS_PATH = "/settings"; function RootLayout() { - const router = useRouter(); - const isSettings = router.state.location.pathname === SETTINGS_PATH; - useEffect(() => { applyTheme(getStoredTheme()); }, []); - if (isSettings) { - return ; - } - return (
=18'} + hasBin: true + '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} @@ -2267,6 +2275,11 @@ packages: resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} engines: {node: '>=14.14'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3199,6 +3212,16 @@ packages: resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} engines: {node: '>=4'} + playwright-core@1.59.1: + resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.59.1: + resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==} + engines: {node: '>=18'} + hasBin: true + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -4586,6 +4609,10 @@ snapshots: '@oxc-project/types@0.127.0': {} + '@playwright/test@1.59.1': + dependencies: + playwright: 1.59.1 + '@pnpm/config.env-replace@1.1.0': {} '@pnpm/network.ca-file@1.0.2': @@ -5969,6 +5996,9 @@ snapshots: jsonfile: 6.2.1 universalify: 2.0.1 + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -6955,6 +6985,14 @@ snapshots: find-up: 2.1.0 load-json-file: 4.0.0 + playwright-core@1.59.1: {} + + playwright@1.59.1: + dependencies: + playwright-core: 1.59.1 + optionalDependencies: + fsevents: 2.3.2 + pluralize@8.0.0: {} postcss@8.5.10: