+
diff --git a/src/evently.client/src/routes/gatherings/-index.test.tsx b/src/evently.client/src/routes/gatherings/-index.test.tsx
new file mode 100644
index 0000000..021b44c
--- /dev/null
+++ b/src/evently.client/src/routes/gatherings/-index.test.tsx
@@ -0,0 +1,37 @@
+import { render, screen, waitFor } from "@testing-library/react";
+import { getMockGatherings } from "~/lib/services/gathering-service.mock";
+import * as GatheringService from "~/lib/services";
+import userEvent from "@testing-library/user-event";
+import { TestWrapper, WrapperDataTestId } from "~/lib/components";
+import { GatheringsPage } from "./index.tsx";
+import type { GetGatheringsParams } from "~/lib/services";
+
+it("renders GatheringPage", async () => {
+ const spy = vi.spyOn(GatheringService, "getGatherings");
+ spy.mockImplementation(async (params: GetGatheringsParams) => await getMockGatherings(params));
+
+ render(
+
+
+
+ );
+ await waitFor(() => screen.findByTestId(WrapperDataTestId));
+
+ expect(spy).toHaveBeenCalledTimes(1);
+ let element = await screen.findByText("Tech Conference 2024");
+ expect(element).toBeInTheDocument();
+
+ element = await screen.findByText("Design Workshop");
+ expect(element).toBeInTheDocument();
+
+ element = await screen.findByText("Networking Event");
+ expect(element).toBeInTheDocument();
+
+ const input: HTMLInputElement = screen.getByPlaceholderText("Search Gatherings");
+ await userEvent.type(input, "T");
+ expect(spy).toHaveBeenCalledTimes(2);
+
+ const button: HTMLButtonElement = screen.getByRole("button", { name: "»" });
+ await userEvent.click(button);
+ expect(spy).toHaveBeenCalledTimes(3);
+});
diff --git a/src/evently.client/src/routes/gatherings/index.tsx b/src/evently.client/src/routes/gatherings/index.tsx
index 85d2bd9..63e176c 100644
--- a/src/evently.client/src/routes/gatherings/index.tsx
+++ b/src/evently.client/src/routes/gatherings/index.tsx
@@ -4,8 +4,8 @@ import { useQuery } from "@tanstack/react-query";
import { Gathering } from "~/lib/domains/entities";
import { getGatherings, type GetGatheringsParams } from "~/lib/services";
import { Card } from "~/lib/components";
-import type { PageResult } from "~/lib/domains/models";
import { Icon } from "@iconify/react";
+import type { PageResult } from "~/lib/domains/interfaces";
export const Route = createFileRoute("/gatherings/")({
component: GatheringsPage,
diff --git a/src/evently.client/src/routes/healthcheck/-index.test.tsx b/src/evently.client/src/routes/healthcheck/-index.test.tsx
new file mode 100644
index 0000000..a5a6540
--- /dev/null
+++ b/src/evently.client/src/routes/healthcheck/-index.test.tsx
@@ -0,0 +1,55 @@
+import { render, screen, waitFor } from "@testing-library/react";
+import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
+import * as healthCheckService from "./-services/health-check-service";
+import { HealthcheckPage } from "./index.tsx";
+import { TestWrapper, WrapperDataTestId } from "~/lib/components";
+
+// Mock the health check service
+vi.mock("./-services/health-check-service", () => ({
+ getStatus: vi.fn()
+}));
+
+const mockGetStatus = vi.mocked(healthCheckService.getStatus);
+
+describe("HealthcheckPage", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ afterEach(() => {
+ vi.resetAllMocks();
+ });
+
+ it("should render loading state initially", async () => {
+ mockGetStatus.mockReturnValue(new Promise(() => {})); // Never resolving with a promise
+ render(
+
+
+
+ );
+ await waitFor(() => screen.findByTestId(WrapperDataTestId));
+
+ expect(screen.getByText("Loading...")).toBeInTheDocument();
+ });
+
+ it("should render health statuses when data is loaded successfully", async () => {
+ const mockStatuses = {
+ Database: "Healthy",
+ API: "Healthy"
+ };
+
+ mockGetStatus.mockResolvedValue(mockStatuses);
+
+ render(
+
+
+
+ );
+ await screen.findByTestId("root-layout");
+
+ // Check that all status entries are rendered
+ // await router.navigate({ to: "/healthcheck" });
+ expect(screen.getByText("Database: Healthy")).toBeInTheDocument();
+ expect(screen.getByText("API: Healthy")).toBeInTheDocument();
+ });
+});
diff --git a/src/evently.client/src/routes/healthcheck/index.tsx b/src/evently.client/src/routes/healthcheck/index.tsx
index ae5deea..6c465f6 100644
--- a/src/evently.client/src/routes/healthcheck/index.tsx
+++ b/src/evently.client/src/routes/healthcheck/index.tsx
@@ -15,15 +15,15 @@ export function HealthcheckPage(): JSX.Element {
const statuses: Record
= _statuses ?? {};
return (
-
+
{isLoading ? (
Loading...
) : (
<>
{Object.entries(statuses).map(([key, value]) => (
-
+
{key}: {value}
-
+
))}
>
)}
diff --git a/src/evently.client/src/routes/login/callback.tsx b/src/evently.client/src/routes/login/callback.tsx
deleted file mode 100644
index c2b27de..0000000
--- a/src/evently.client/src/routes/login/callback.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { createFileRoute, useNavigate } from "@tanstack/react-router";
-import { useEffect } from "react";
-import { getAccount } from "~/lib/services";
-
-export const Route = createFileRoute("/login/callback")({
- component: LoginCallbackPage,
- beforeLoad: async () => {
- const account = await getAccount();
- return { account };
- }
-});
-export function LoginCallbackPage() {
- const navigate = useNavigate();
- useEffect(() => {
- navigate({ to: "/bookings/attending" }).then();
- }, [navigate]);
-}
diff --git a/src/evently.client/src/routes/login/index.tsx b/src/evently.client/src/routes/login/index.tsx
index a879d78..002592a 100644
--- a/src/evently.client/src/routes/login/index.tsx
+++ b/src/evently.client/src/routes/login/index.tsx
@@ -7,7 +7,7 @@ export const Route = createFileRoute("/login/")({
});
export function LoginPage() {
- const defaultRedirect: URL = new URL("/login/callback", window.location.href);
+ const defaultRedirect: URL = new URL("/bookings/attending", window.location.href);
const searchParams: Record
= useSearch({ strict: false });
const redirect: string = searchParams["redirect"] ?? defaultRedirect.href;
console.log({ redirect });
diff --git a/src/evently.client/src/setup-tests.ts b/src/evently.client/src/setup-tests.ts
new file mode 100644
index 0000000..f149f27
--- /dev/null
+++ b/src/evently.client/src/setup-tests.ts
@@ -0,0 +1 @@
+import "@testing-library/jest-dom/vitest";
diff --git a/src/evently.client/src/vite-env.d.ts b/src/evently.client/src/vite-env.d.ts
index c8cbea0..dc2737f 100644
--- a/src/evently.client/src/vite-env.d.ts
+++ b/src/evently.client/src/vite-env.d.ts
@@ -1,2 +1,2 @@
///
-// Register the router instance for type safety
+///
diff --git a/src/evently.client/tsconfig.app.json b/src/evently.client/tsconfig.app.json
index 4b53749..6ff0d73 100644
--- a/src/evently.client/tsconfig.app.json
+++ b/src/evently.client/tsconfig.app.json
@@ -6,6 +6,7 @@
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
+ "types": ["vitest/globals", "@testing-library/jest-dom"],
/* Bundler mode */
"moduleResolution": "bundler",
diff --git a/src/evently.client/vite.config.ts b/src/evently.client/vite.config.ts
index 0d20874..9b745d9 100644
--- a/src/evently.client/vite.config.ts
+++ b/src/evently.client/vite.config.ts
@@ -1,10 +1,10 @@
-import { defineConfig } from "vite";
import { env } from "process";
import { generatePem, getBackendUrl, type KeyCertPair } from "./aspnetcore-https.ts";
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { tanstackRouter } from "@tanstack/router-plugin/vite";
import { fileURLToPath, URL } from "node:url";
+import { defineConfig } from "vitest/config";
const keyCert: KeyCertPair = generatePem();
const { key, cert } = keyCert;
@@ -13,6 +13,12 @@ console.log({ backendUrl });
// https://vitejs.dev/config/
export default defineConfig({
+ test: {
+ include: ["src/**/*.{test,spec}.{js,ts,jsx,tsx}"],
+ environment: "jsdom",
+ setupFiles: "src/setup-tests.ts",
+ globals: true
+ },
plugins: [
tailwindcss(),
// Please make sure that '@tanstack/router-plugin' is passed before '@vitejs/plugin-react'