Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/frontend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,29 @@ jobs:
working-directory: frontend
run: npm run test

build:
name: Build Frontend
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
working-directory: frontend
run: npm ci

- name: Build frontend
working-directory: frontend
run: npm run build

ui-tests:
name: UI Tests
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ vi.mock("prism-react-renderer", () => ({
tokens: code
.split("\n")
.map((line: string) => [{content: line, types: ["plain"]}]),
getLineProps: ({line}: any) => ({}),
getLineProps: (_lineProps: any) => ({}),
getTokenProps: ({token}: any) => ({children: token.content}),
}),
themes: {nightOwl: {plain: {}}, github: {plain: {}}},
Expand Down
23 changes: 21 additions & 2 deletions frontend/src/components/utils/__tests__/Toaster.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,21 @@ import {render, screen} from "@testing-library/react";
import {beforeEach, describe, expect, it, vi} from "vitest";
import {Toaster} from "../Toaster";

const mockSonner = vi.hoisted(() => vi.fn(() => <div data-testid="sonner" />));
type SonnerProps = {
className?: string;
position?: string;
toastOptions?: {
classNames?: {
toast?: string;
success?: string;
error?: string;
};
};
};

const mockSonner = vi.hoisted(() =>
vi.fn((_props: SonnerProps) => <div data-testid="sonner" />),
);

vi.mock("sonner", () => ({
Toaster: (props: any) => mockSonner(props),
Expand All @@ -19,7 +33,12 @@ describe("Toaster", () => {
expect(screen.getByTestId("sonner")).toBeInTheDocument();
expect(mockSonner).toHaveBeenCalledTimes(1);

const sonnerProps = mockSonner.mock.calls[0][0];
const sonnerProps = mockSonner.mock.calls[0]?.[0];
expect(sonnerProps).toBeDefined();
if (!sonnerProps) {
throw new Error("Expected Sonner to be called with props");
}

expect(sonnerProps.className).toBe("toaster group");
expect(sonnerProps.position).toBe("bottom-right");
expect(sonnerProps.toastOptions).toEqual(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ describe("useAuthMutations", () => {

await act(async () => {
result.current.mutate({
old_password: "old",
current_password: "old",
new_password: "new",
});
});

await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(changePassword).toHaveBeenCalledWith({
old_password: "old",
current_password: "old",
new_password: "new",
});
});
Expand All @@ -142,7 +142,7 @@ describe("useAuthMutations", () => {

await act(async () => {
result.current.mutate({
old_password: "old",
current_password: "old",
new_password: "new",
});
});
Expand Down
12 changes: 9 additions & 3 deletions frontend/src/routes/__tests__/-authRoute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ describe("routes/_auth beforeLoad", () => {
it("redirects to /login when auth_token is missing", async () => {
const {Route, ensureQueryDataMock} = await loadAuthRoute();

await expect(Route.options.beforeLoad?.()).rejects.toMatchObject({
await expect(
Route.options.beforeLoad?.({} as never),
).rejects.toMatchObject({
options: {to: "/login"},
});
expect(ensureQueryDataMock).not.toHaveBeenCalled();
Expand All @@ -66,7 +68,9 @@ describe("routes/_auth beforeLoad", () => {
const {Route, queryKeysMock, ensureQueryDataMock, meMock} =
await loadAuthRoute();

await expect(Route.options.beforeLoad?.()).resolves.toBeUndefined();
await expect(
Route.options.beforeLoad?.({} as never),
).resolves.toBeUndefined();
expect(ensureQueryDataMock).toHaveBeenCalledWith(
expect.objectContaining({
queryKey: queryKeysMock.auth.me,
Expand All @@ -82,6 +86,8 @@ describe("routes/_auth beforeLoad", () => {
const authError = new Error("me query failed");
meMock.mockRejectedValueOnce(authError);

await expect(Route.options.beforeLoad?.()).rejects.toBe(authError);
await expect(Route.options.beforeLoad?.({} as never)).rejects.toBe(
authError,
);
});
});
4 changes: 2 additions & 2 deletions frontend/src/routes/__tests__/-redirectRoutes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import {Route as ProjectIndexRoute} from "../_auth/project/$projectId/index";
describe("redirect-only routes", () => {
it("redirects /_auth/ to /dashboard", async () => {
await expect(
(async () => AuthIndexRoute.options.beforeLoad?.())(),
(async () => AuthIndexRoute.options.beforeLoad?.({} as never))(),
).rejects.toMatchObject({
options: {to: "/dashboard"},
});
});

it("redirects /_auth/project/$projectId/ to /dashboard with replace", async () => {
await expect(
(async () => ProjectIndexRoute.options.beforeLoad?.())(),
(async () => ProjectIndexRoute.options.beforeLoad?.({} as never))(),
).rejects.toMatchObject({
options: {
to: "/dashboard",
Expand Down
Loading