Fix and update tests
CI Pipeline / test (20) (pull_request) Failing after 2m41s
CI Pipeline / test (18) (pull_request) Failing after 4m30s
CI Pipeline / e2e (firefox) (pull_request) Successful in 3m17s
CI Pipeline / e2e (webkit) (pull_request) Successful in 3m40s
CI Pipeline / e2e (chromium) (pull_request) Successful in 11m13s
CI Pipeline / visual-regression (pull_request) Successful in 6m7s
CI Pipeline / performance (pull_request) Failing after 3m40s
CI Pipeline / storybook (pull_request) Successful in 1m14s
CI Pipeline / build (pull_request) Successful in 1m37s
CI Pipeline / test (20) (pull_request) Failing after 2m41s
CI Pipeline / test (18) (pull_request) Failing after 4m30s
CI Pipeline / e2e (firefox) (pull_request) Successful in 3m17s
CI Pipeline / e2e (webkit) (pull_request) Successful in 3m40s
CI Pipeline / e2e (chromium) (pull_request) Successful in 11m13s
CI Pipeline / visual-regression (pull_request) Successful in 6m7s
CI Pipeline / performance (pull_request) Failing after 3m40s
CI Pipeline / storybook (pull_request) Successful in 1m14s
CI Pipeline / build (pull_request) Successful in 1m37s
This commit is contained in:
@@ -9,7 +9,7 @@ export type ValidationRule<T = string> = (value: T) => string | null;
|
|||||||
* Validation rules for common patterns
|
* Validation rules for common patterns
|
||||||
*/
|
*/
|
||||||
export const validationRules = {
|
export const validationRules = {
|
||||||
required: <T>(value: T): string | null => {
|
required: (value: unknown): string | null => {
|
||||||
if (value === null || value === undefined || value === "") {
|
if (value === null || value === undefined || value === "") {
|
||||||
return "This field is required";
|
return "This field is required";
|
||||||
}
|
}
|
||||||
|
|||||||
+89
-58
@@ -1,9 +1,9 @@
|
|||||||
import { describe, test, expect } from "vitest";
|
import { describe, test, expect } from "vitest";
|
||||||
import { render, screen } from "@testing-library/react";
|
import { render, screen, waitFor } from "@testing-library/react";
|
||||||
import Page from "../../app/page";
|
import Page from "../../app/page";
|
||||||
|
|
||||||
describe("Page", () => {
|
describe("Page", () => {
|
||||||
test("renders all main sections", () => {
|
test("renders all main sections", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check that all main sections are rendered (using getAllByText since there are multiple instances)
|
// Check that all main sections are rendered (using getAllByText since there are multiple instances)
|
||||||
@@ -15,10 +15,13 @@ describe("Page", () => {
|
|||||||
).length,
|
).length,
|
||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Wait for dynamically imported components to load
|
||||||
// Check numbered cards section (using getAllByText since there are multiple instances)
|
// Check numbered cards section (using getAllByText since there are multiple instances)
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText("How CommunityRule works").length,
|
expect(
|
||||||
).toBeGreaterThan(0);
|
screen.getAllByText("How CommunityRule works").length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByText(
|
screen.getAllByText(
|
||||||
"Here's a quick overview of the process, from start to finish.",
|
"Here's a quick overview of the process, from start to finish.",
|
||||||
@@ -60,13 +63,15 @@ describe("Page", () => {
|
|||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders numbered cards with correct data", () => {
|
test("renders numbered cards with correct data", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check numbered cards content (using getAllByText since there are multiple instances)
|
// Wait for dynamically imported NumberedCards component to load
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText("How CommunityRule works").length,
|
expect(
|
||||||
).toBeGreaterThan(0);
|
screen.getAllByText("How CommunityRule works").length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByText(
|
screen.getAllByText(
|
||||||
"Here's a quick overview of the process, from start to finish.",
|
"Here's a quick overview of the process, from start to finish.",
|
||||||
@@ -89,13 +94,15 @@ describe("Page", () => {
|
|||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders feature grid with correct data", () => {
|
test("renders feature grid with correct data", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check feature grid content (using getAllByText since there are multiple instances)
|
// Wait for dynamically imported FeatureGrid component to load
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText("We've got your back, every step of the way").length,
|
expect(
|
||||||
).toBeGreaterThan(0);
|
screen.getAllByText("We've got your back, every step of the way").length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByText(
|
screen.getAllByText(
|
||||||
"Use our toolkit to improve, document, and evolve your organization.",
|
"Use our toolkit to improve, document, and evolve your organization.",
|
||||||
@@ -116,24 +123,29 @@ describe("Page", () => {
|
|||||||
expect(screen.getAllByText("Ask an organizer").length).toBeGreaterThan(0);
|
expect(screen.getAllByText("Ask an organizer").length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders all component sections", () => {
|
test("renders all component sections", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check that all major components are present by looking for their content
|
// Check that all major components are present by looking for their content
|
||||||
// HeroBanner
|
// HeroBanner
|
||||||
expect(screen.getAllByText("Collaborate").length).toBeGreaterThan(0);
|
expect(screen.getAllByText("Collaborate").length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Wait for dynamically imported components to load
|
||||||
// LogoWall - should be present (even if just the component structure)
|
// LogoWall - should be present (even if just the component structure)
|
||||||
// NumberedCards
|
// NumberedCards
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText("How CommunityRule works").length,
|
expect(
|
||||||
).toBeGreaterThan(0);
|
screen.getAllByText("How CommunityRule works").length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
// RuleStack - should be present
|
// RuleStack - should be present
|
||||||
// FeatureGrid
|
// FeatureGrid
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText("We've got your back, every step of the way").length,
|
expect(
|
||||||
).toBeGreaterThan(0);
|
screen.getAllByText("We've got your back, every step of the way").length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
// QuoteBlock - should be present
|
// QuoteBlock - should be present
|
||||||
// AskOrganizer
|
// AskOrganizer
|
||||||
@@ -161,7 +173,7 @@ describe("Page", () => {
|
|||||||
expect(screen.getAllByText("Ask an organizer").length).toBeGreaterThan(0);
|
expect(screen.getAllByText("Ask an organizer").length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders descriptive text content", () => {
|
test("renders descriptive text content", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check main description (using getAllByText since there are multiple instances)
|
// Check main description (using getAllByText since there are multiple instances)
|
||||||
@@ -171,19 +183,23 @@ describe("Page", () => {
|
|||||||
).length,
|
).length,
|
||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
|
|
||||||
// Check numbered cards description (using getAllByText since there are multiple instances)
|
// Wait for dynamically imported NumberedCards component
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText(
|
expect(
|
||||||
"Here's a quick overview of the process, from start to finish.",
|
screen.getAllByText(
|
||||||
).length,
|
"Here's a quick overview of the process, from start to finish.",
|
||||||
).toBeGreaterThan(0);
|
).length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
// Check feature grid description (using getAllByText since there are multiple instances)
|
// Wait for dynamically imported FeatureGrid component
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText(
|
expect(
|
||||||
"Use our toolkit to improve, document, and evolve your organization.",
|
screen.getAllByText(
|
||||||
).length,
|
"Use our toolkit to improve, document, and evolve your organization.",
|
||||||
).toBeGreaterThan(0);
|
).length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
// Check ask organizer description (using getAllByText since there are multiple instances)
|
// Check ask organizer description (using getAllByText since there are multiple instances)
|
||||||
expect(
|
expect(
|
||||||
@@ -191,29 +207,38 @@ describe("Page", () => {
|
|||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders section titles correctly", () => {
|
test("renders section titles correctly", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check all section titles (using getAllByText since there are multiple instances)
|
// Check all section titles (using getAllByText since there are multiple instances)
|
||||||
expect(screen.getAllByText("Collaborate").length).toBeGreaterThan(0);
|
expect(screen.getAllByText("Collaborate").length).toBeGreaterThan(0);
|
||||||
expect(
|
|
||||||
screen.getAllByText("How CommunityRule works").length,
|
// Wait for dynamically imported components
|
||||||
).toBeGreaterThan(0);
|
await waitFor(() => {
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByText("We've got your back, every step of the way").length,
|
screen.getAllByText("How CommunityRule works").length,
|
||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
screen.getAllByText("We've got your back, every step of the way").length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
expect(screen.getAllByText("Still have questions?").length).toBeGreaterThan(
|
expect(screen.getAllByText("Still have questions?").length).toBeGreaterThan(
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders numbered card items with correct content", () => {
|
test("renders numbered card items with correct content", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check all three numbered card items (using getAllByText since there are multiple instances)
|
// Wait for dynamically imported NumberedCards component
|
||||||
expect(
|
await waitFor(() => {
|
||||||
screen.getAllByText("Document how your community makes decisions").length,
|
// Check all three numbered card items (using getAllByText since there are multiple instances)
|
||||||
).toBeGreaterThan(0);
|
expect(
|
||||||
|
screen.getAllByText("Document how your community makes decisions").length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByText(
|
screen.getAllByText(
|
||||||
"Build an operating manual for a successful community",
|
"Build an operating manual for a successful community",
|
||||||
@@ -226,21 +251,27 @@ describe("Page", () => {
|
|||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders subtitle content correctly", () => {
|
test("renders subtitle content correctly", async () => {
|
||||||
render(<Page />);
|
render(<Page />);
|
||||||
|
|
||||||
// Check subtitles (using getAllByText since there are multiple instances)
|
// Check subtitles (using getAllByText since there are multiple instances)
|
||||||
expect(screen.getAllByText("with clarity").length).toBeGreaterThan(0);
|
expect(screen.getAllByText("with clarity").length).toBeGreaterThan(0);
|
||||||
expect(
|
|
||||||
screen.getAllByText(
|
// Wait for dynamically imported components
|
||||||
"Here's a quick overview of the process, from start to finish.",
|
await waitFor(() => {
|
||||||
).length,
|
expect(
|
||||||
).toBeGreaterThan(0);
|
screen.getAllByText(
|
||||||
expect(
|
"Here's a quick overview of the process, from start to finish.",
|
||||||
screen.getAllByText(
|
).length,
|
||||||
"Use our toolkit to improve, document, and evolve your organization.",
|
).toBeGreaterThan(0);
|
||||||
).length,
|
});
|
||||||
).toBeGreaterThan(0);
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
screen.getAllByText(
|
||||||
|
"Use our toolkit to improve, document, and evolve your organization.",
|
||||||
|
).length,
|
||||||
|
).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByText("Get answers from an experienced organizer").length,
|
screen.getAllByText("Get answers from an experienced organizer").length,
|
||||||
).toBeGreaterThan(0);
|
).toBeGreaterThan(0);
|
||||||
|
|||||||
+36
-1
@@ -1,5 +1,5 @@
|
|||||||
import "@testing-library/jest-dom/vitest";
|
import "@testing-library/jest-dom/vitest";
|
||||||
import { afterAll, afterEach, beforeAll } from "vitest";
|
import { afterAll, afterEach, beforeAll, vi } from "vitest";
|
||||||
import { cleanup } from "@testing-library/react";
|
import { cleanup } from "@testing-library/react";
|
||||||
import { server } from "./tests/msw/server";
|
import { server } from "./tests/msw/server";
|
||||||
// Note: Tailwind CSS v4 uses syntax that jsdom can't parse
|
// Note: Tailwind CSS v4 uses syntax that jsdom can't parse
|
||||||
@@ -7,6 +7,41 @@ import { server } from "./tests/msw/server";
|
|||||||
// Design tokens are accessible via CSS variables in the DOM
|
// Design tokens are accessible via CSS variables in the DOM
|
||||||
// If you need to test CSS, use a CSS transformer or mock the import
|
// If you need to test CSS, use a CSS transformer or mock the import
|
||||||
|
|
||||||
|
// Mock next/dynamic for tests - return components directly instead of lazy loading
|
||||||
|
vi.mock("next/dynamic", () => {
|
||||||
|
const React = require("react");
|
||||||
|
return {
|
||||||
|
default: (importFn: () => Promise<any>, options?: any) => {
|
||||||
|
// In tests, return a component that immediately resolves and renders
|
||||||
|
return function DynamicComponent(props: any) {
|
||||||
|
const [Component, setComponent] = React.useState(null);
|
||||||
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
importFn()
|
||||||
|
.then((mod: any) => {
|
||||||
|
setComponent(mod.default || mod);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading && options?.loading) {
|
||||||
|
return options.loading();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Component) {
|
||||||
|
return React.createElement(Component, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// MSW for API integration tests (mock fetch)
|
// MSW for API integration tests (mock fetch)
|
||||||
beforeAll(() => server.listen({ onUnhandledRequest: "bypass" }));
|
beforeAll(() => server.listen({ onUnhandledRequest: "bypass" }));
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user