Merge pull request #1 from offendingcommit/fix/web-settings-and-demo-provider
fix(web): settings shows on first load + global DemoProvider
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
"build": "turbo run build",
|
"build": "turbo run build",
|
||||||
"lint": "turbo run lint",
|
"lint": "turbo run lint",
|
||||||
"test": "turbo run test",
|
"test": "turbo run test",
|
||||||
|
"test:e2e": "turbo run test:e2e",
|
||||||
"typecheck": "turbo run typecheck",
|
"typecheck": "turbo run typecheck",
|
||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
|
|||||||
2
packages/web/.gitignore
vendored
Normal file
2
packages/web/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
test-results/
|
||||||
|
playwright-report/
|
||||||
29
packages/web/e2e/sidebar.spec.ts
Normal file
29
packages/web/e2e/sidebar.spec.ts
Normal file
@@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -10,12 +10,10 @@
|
|||||||
"lint": "biome check src/",
|
"lint": "biome check src/",
|
||||||
"lint:fix": "biome check --write src/",
|
"lint:fix": "biome check --write src/",
|
||||||
"test": "vitest run --passWithNoTests",
|
"test": "vitest run --passWithNoTests",
|
||||||
|
"test:e2e": "playwright test",
|
||||||
"generate:api": "openapi-typescript openapi.json -o src/api/schema.d.ts"
|
"generate:api": "openapi-typescript openapi.json -o src/api/schema.d.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2",
|
|
||||||
"@tauri-apps/plugin-http": "^2",
|
|
||||||
"@tauri-apps/plugin-shell": "^2",
|
|
||||||
"@fontsource/dm-mono": "^5.2.7",
|
"@fontsource/dm-mono": "^5.2.7",
|
||||||
"@fontsource/dm-sans": "^5.2.8",
|
"@fontsource/dm-sans": "^5.2.8",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
@@ -27,6 +25,9 @@
|
|||||||
"@tailwindcss/vite": "^4.2.4",
|
"@tailwindcss/vite": "^4.2.4",
|
||||||
"@tanstack/react-query": "^5.74.4",
|
"@tanstack/react-query": "^5.74.4",
|
||||||
"@tanstack/react-router": "^1.120.3",
|
"@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",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^12.38.0",
|
"framer-motion": "^12.38.0",
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
"zod": "catalog:"
|
"zod": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "catalog:",
|
||||||
"@tanstack/router-plugin": "^1.120.3",
|
"@tanstack/router-plugin": "^1.120.3",
|
||||||
"@testing-library/jest-dom": "catalog:",
|
"@testing-library/jest-dom": "catalog:",
|
||||||
"@testing-library/react": "catalog:",
|
"@testing-library/react": "catalog:",
|
||||||
|
|||||||
17
packages/web/playwright.config.ts
Normal file
17
packages/web/playwright.config.ts
Normal file
@@ -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,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|||||||
import { createRouter, RouterProvider } from "@tanstack/react-router";
|
import { createRouter, RouterProvider } from "@tanstack/react-router";
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
|
import { DemoProvider } from "./context/DemoContext";
|
||||||
import { routeTree } from "./routeTree.gen";
|
import { routeTree } from "./routeTree.gen";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|
||||||
@@ -32,7 +33,9 @@ if (!root) throw new Error("Missing #root element");
|
|||||||
createRoot(root).render(
|
createRoot(root).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<RouterProvider router={router} />
|
<DemoProvider>
|
||||||
|
<RouterProvider router={router} />
|
||||||
|
</DemoProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,46 +1,36 @@
|
|||||||
import { createRootRoute, Outlet, useRouter } from "@tanstack/react-router";
|
import { createRootRoute, Outlet, redirect } from "@tanstack/react-router";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Sidebar } from "@/components/layout/Sidebar";
|
import { Sidebar } from "@/components/layout/Sidebar";
|
||||||
import { DemoProvider } from "@/context/DemoContext";
|
|
||||||
import { loadConfig } from "@/lib/config";
|
import { loadConfig } from "@/lib/config";
|
||||||
import { applyTheme, getStoredTheme } from "@/lib/theme";
|
import { applyTheme, getStoredTheme } from "@/lib/theme";
|
||||||
|
|
||||||
function RootLayout() {
|
const SETTINGS_PATH = "/settings";
|
||||||
const config = loadConfig();
|
|
||||||
const router = useRouter();
|
|
||||||
const isSettings = router.state.location.pathname === "/settings";
|
|
||||||
|
|
||||||
|
function RootLayout() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
applyTheme(getStoredTheme());
|
applyTheme(getStoredTheme());
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!config && !isSettings) {
|
|
||||||
router.navigate({ to: "/settings" as never });
|
|
||||||
}
|
|
||||||
}, [config, isSettings, router]);
|
|
||||||
|
|
||||||
if (isSettings) {
|
|
||||||
return <Outlet />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DemoProvider>
|
<div
|
||||||
<div
|
className="flex h-screen w-full overflow-hidden"
|
||||||
className="flex h-screen w-full overflow-hidden"
|
style={{ background: "var(--bg)", position: "relative", zIndex: 1 }}
|
||||||
style={{ background: "var(--bg)", position: "relative", zIndex: 1 }}
|
>
|
||||||
>
|
<Sidebar />
|
||||||
<Sidebar />
|
<main className="flex-1 overflow-auto" style={{ position: "relative", zIndex: 1 }}>
|
||||||
<main className="flex-1 overflow-auto" style={{ position: "relative", zIndex: 1 }}>
|
<Outlet />
|
||||||
<Outlet />
|
</main>
|
||||||
</main>
|
</div>
|
||||||
</div>
|
|
||||||
</DemoProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
|
beforeLoad: ({ location }) => {
|
||||||
|
// Redirect to settings synchronously when no config is present, so the
|
||||||
|
// first paint already shows the settings form instead of a blank screen.
|
||||||
|
if (location.pathname !== SETTINGS_PATH && !loadConfig()) {
|
||||||
|
throw redirect({ to: SETTINGS_PATH as never });
|
||||||
|
}
|
||||||
|
},
|
||||||
component: RootLayout,
|
component: RootLayout,
|
||||||
});
|
});
|
||||||
|
|||||||
68
packages/web/src/test/app.test.tsx
Normal file
68
packages/web/src/test/app.test.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
import { createMemoryHistory, createRouter, RouterProvider } from "@tanstack/react-router";
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { DemoProvider } from "@/context/DemoContext";
|
||||||
|
import { useDemo } from "@/hooks/useDemo";
|
||||||
|
import { routeTree } from "@/routeTree.gen";
|
||||||
|
|
||||||
|
function renderAt(initialPath: string) {
|
||||||
|
const router = createRouter({
|
||||||
|
routeTree,
|
||||||
|
history: createMemoryHistory({ initialEntries: [initialPath] }),
|
||||||
|
});
|
||||||
|
const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||||
|
return render(
|
||||||
|
<QueryClientProvider client={qc}>
|
||||||
|
<DemoProvider>
|
||||||
|
{/* biome-ignore lint/suspicious/noExplicitAny: test router type */}
|
||||||
|
<RouterProvider router={router as any} />
|
||||||
|
</DemoProvider>
|
||||||
|
</QueryClientProvider>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("first load with no config", () => {
|
||||||
|
it("renders the settings form on first paint when no config exists", async () => {
|
||||||
|
localStorage.clear();
|
||||||
|
renderAt("/");
|
||||||
|
// Should be visible immediately — bug 1: RootLayout returns null while
|
||||||
|
// a useEffect-driven navigate fires, leaving a blank screen.
|
||||||
|
expect(
|
||||||
|
await screen.findByText(/Connect to your self-hosted Honcho instance/i),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Sidebar/useDemo availability across routes", () => {
|
||||||
|
it("does not throw when a useDemo consumer mounts alongside the routed app", () => {
|
||||||
|
function DemoConsumer() {
|
||||||
|
const { demo } = useDemo();
|
||||||
|
return <span data-testid="demo-flag">{String(demo)}</span>;
|
||||||
|
}
|
||||||
|
// After the fix, DemoProvider wraps the app at the root (main.tsx /
|
||||||
|
// __root.tsx) so consumers anywhere in the tree resolve. This test
|
||||||
|
// renders a consumer as a sibling of the router under the same provider
|
||||||
|
// the production wiring uses.
|
||||||
|
localStorage.clear();
|
||||||
|
expect(() => {
|
||||||
|
const router = createRouter({
|
||||||
|
routeTree,
|
||||||
|
history: createMemoryHistory({ initialEntries: ["/settings"] }),
|
||||||
|
});
|
||||||
|
const qc = new QueryClient({
|
||||||
|
defaultOptions: { queries: { retry: false } },
|
||||||
|
});
|
||||||
|
render(
|
||||||
|
<QueryClientProvider client={qc}>
|
||||||
|
<DemoProvider>
|
||||||
|
{/* biome-ignore lint/suspicious/noExplicitAny: test router type */}
|
||||||
|
<RouterProvider router={router as any} />
|
||||||
|
<DemoConsumer />
|
||||||
|
</DemoProvider>
|
||||||
|
</QueryClientProvider>,
|
||||||
|
);
|
||||||
|
}).not.toThrow();
|
||||||
|
expect(screen.getByTestId("demo-flag")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
26
packages/web/src/test/setup.ts
Normal file
26
packages/web/src/test/setup.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import "@testing-library/jest-dom/vitest";
|
||||||
|
import { cleanup } from "@testing-library/react";
|
||||||
|
import { afterEach, vi } from "vitest";
|
||||||
|
|
||||||
|
// jsdom doesn't implement matchMedia; theme code reads it on mount.
|
||||||
|
if (!window.scrollTo) {
|
||||||
|
window.scrollTo = vi.fn() as unknown as typeof window.scrollTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.matchMedia) {
|
||||||
|
window.matchMedia = vi.fn().mockImplementation((query: string) => ({
|
||||||
|
matches: false,
|
||||||
|
media: query,
|
||||||
|
onchange: null,
|
||||||
|
addListener: vi.fn(),
|
||||||
|
removeListener: vi.fn(),
|
||||||
|
addEventListener: vi.fn(),
|
||||||
|
removeEventListener: vi.fn(),
|
||||||
|
dispatchEvent: vi.fn(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
cleanup();
|
||||||
|
localStorage.clear();
|
||||||
|
});
|
||||||
26
packages/web/vitest.config.ts
Normal file
26
packages/web/vitest.config.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import react from "@vitejs/plugin-react";
|
||||||
|
import { defineConfig } from "vitest/config";
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@": path.resolve(__dirname, "./src"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
define: {
|
||||||
|
__APP_VERSION__: JSON.stringify("0.0.0-test"),
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
environment: "jsdom",
|
||||||
|
globals: true,
|
||||||
|
setupFiles: ["./src/test/setup.ts"],
|
||||||
|
css: false,
|
||||||
|
include: ["src/**/*.{test,spec}.{ts,tsx}"],
|
||||||
|
exclude: ["node_modules", "dist", "e2e"],
|
||||||
|
},
|
||||||
|
});
|
||||||
41
pnpm-lock.yaml
generated
41
pnpm-lock.yaml
generated
@@ -9,6 +9,9 @@ catalogs:
|
|||||||
'@biomejs/biome':
|
'@biomejs/biome':
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.4.13
|
version: 2.4.13
|
||||||
|
'@playwright/test':
|
||||||
|
specifier: ^1.59.1
|
||||||
|
version: 1.59.1
|
||||||
'@testing-library/jest-dom':
|
'@testing-library/jest-dom':
|
||||||
specifier: ^6.6.3
|
specifier: ^6.6.3
|
||||||
version: 6.9.1
|
version: 6.9.1
|
||||||
@@ -192,6 +195,9 @@ importers:
|
|||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.3.6
|
version: 4.3.6
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@playwright/test':
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 1.59.1
|
||||||
'@tanstack/router-plugin':
|
'@tanstack/router-plugin':
|
||||||
specifier: ^1.120.3
|
specifier: ^1.120.3
|
||||||
version: 1.167.23(@tanstack/react-router@1.168.23(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))
|
version: 1.167.23(@tanstack/react-router@1.168.23(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))
|
||||||
@@ -837,6 +843,11 @@ packages:
|
|||||||
'@oxc-project/types@0.127.0':
|
'@oxc-project/types@0.127.0':
|
||||||
resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==}
|
resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==}
|
||||||
|
|
||||||
|
'@playwright/test@1.59.1':
|
||||||
|
resolution: {integrity: sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
'@pnpm/config.env-replace@1.1.0':
|
'@pnpm/config.env-replace@1.1.0':
|
||||||
resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
|
resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
|
||||||
engines: {node: '>=12.22.0'}
|
engines: {node: '>=12.22.0'}
|
||||||
@@ -2267,6 +2278,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==}
|
resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==}
|
||||||
engines: {node: '>=14.14'}
|
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:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@@ -3199,6 +3215,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==}
|
resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==}
|
||||||
engines: {node: '>=4'}
|
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:
|
pluralize@8.0.0:
|
||||||
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -4586,6 +4612,10 @@ snapshots:
|
|||||||
|
|
||||||
'@oxc-project/types@0.127.0': {}
|
'@oxc-project/types@0.127.0': {}
|
||||||
|
|
||||||
|
'@playwright/test@1.59.1':
|
||||||
|
dependencies:
|
||||||
|
playwright: 1.59.1
|
||||||
|
|
||||||
'@pnpm/config.env-replace@1.1.0': {}
|
'@pnpm/config.env-replace@1.1.0': {}
|
||||||
|
|
||||||
'@pnpm/network.ca-file@1.0.2':
|
'@pnpm/network.ca-file@1.0.2':
|
||||||
@@ -5969,6 +5999,9 @@ snapshots:
|
|||||||
jsonfile: 6.2.1
|
jsonfile: 6.2.1
|
||||||
universalify: 2.0.1
|
universalify: 2.0.1
|
||||||
|
|
||||||
|
fsevents@2.3.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -6955,6 +6988,14 @@ snapshots:
|
|||||||
find-up: 2.1.0
|
find-up: 2.1.0
|
||||||
load-json-file: 4.0.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: {}
|
pluralize@8.0.0: {}
|
||||||
|
|
||||||
postcss@8.5.10:
|
postcss@8.5.10:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ catalog:
|
|||||||
"@biomejs/biome": "^2.4.0"
|
"@biomejs/biome": "^2.4.0"
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
"@playwright/test": "^1.59.1"
|
||||||
"@testing-library/jest-dom": "^6.6.3"
|
"@testing-library/jest-dom": "^6.6.3"
|
||||||
"@testing-library/react": "^16.3.0"
|
"@testing-library/react": "^16.3.0"
|
||||||
"@testing-library/user-event": "^14.6.1"
|
"@testing-library/user-event": "^14.6.1"
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"inputs": ["src/**", "vitest.config.*", "package.json"]
|
"inputs": ["src/**", "vitest.config.*", "package.json"]
|
||||||
},
|
},
|
||||||
|
"test:e2e": {
|
||||||
|
"cache": false,
|
||||||
|
"inputs": ["e2e/**", "src/**", "playwright.config.*", "package.json"]
|
||||||
|
},
|
||||||
"cargo-check": {
|
"cargo-check": {
|
||||||
"inputs": ["src-tauri/src/**", "src-tauri/Cargo.toml", "src-tauri/Cargo.lock"],
|
"inputs": ["src-tauri/src/**", "src-tauri/Cargo.toml", "src-tauri/Cargo.lock"],
|
||||||
"outputs": []
|
"outputs": []
|
||||||
|
|||||||
Reference in New Issue
Block a user