Fix tcs type errors
CI Pipeline / test (20) (pull_request) Successful in 3m13s
CI Pipeline / test (18) (pull_request) Successful in 3m57s
CI Pipeline / e2e (firefox) (pull_request) Successful in 5m6s
CI Pipeline / e2e (webkit) (pull_request) Successful in 5m16s
CI Pipeline / e2e (chromium) (pull_request) Successful in 14m47s
CI Pipeline / performance (pull_request) Successful in 4m32s
CI Pipeline / storybook (pull_request) Successful in 1m35s
CI Pipeline / visual-regression (pull_request) Failing after 9m55s
CI Pipeline / lint (pull_request) Failing after 49s
CI Pipeline / build (pull_request) Successful in 1m48s
CI Pipeline / test (20) (pull_request) Successful in 3m13s
CI Pipeline / test (18) (pull_request) Successful in 3m57s
CI Pipeline / e2e (firefox) (pull_request) Successful in 5m6s
CI Pipeline / e2e (webkit) (pull_request) Successful in 5m16s
CI Pipeline / e2e (chromium) (pull_request) Successful in 14m47s
CI Pipeline / performance (pull_request) Successful in 4m32s
CI Pipeline / storybook (pull_request) Successful in 1m35s
CI Pipeline / visual-regression (pull_request) Failing after 9m55s
CI Pipeline / lint (pull_request) Failing after 49s
CI Pipeline / build (pull_request) Successful in 1m48s
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { AxeBuilder } from "@axe-core/playwright";
|
||||
|
||||
test.describe("Accessibility Testing", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { AxeBuilder } from "@axe-core/playwright";
|
||||
|
||||
export async function runA11y(page, options = {}) {
|
||||
export async function runA11y(page, _options = {}) {
|
||||
const results = await new AxeBuilder({ page })
|
||||
.withTags(["wcag2a", "wcag2aa"])
|
||||
.analyze();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { runA11y } from "./axe";
|
||||
|
||||
test.describe("Homepage", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
|
||||
@@ -58,7 +58,7 @@ test.describe("Performance Monitoring", () => {
|
||||
performanceMonitor.setBaselines(BASELINE_METRICS);
|
||||
});
|
||||
|
||||
test("homepage load performance", async ({ page }) => {
|
||||
test("homepage load performance", async ({ page: _page }) => {
|
||||
const result = await performanceMonitor.measurePageLoad("/");
|
||||
|
||||
// Assert page load time is within budget
|
||||
@@ -83,43 +83,57 @@ test.describe("Performance Monitoring", () => {
|
||||
await page.waitForLoadState("networkidle");
|
||||
|
||||
// Get Core Web Vitals with timeout
|
||||
const coreWebVitals = await page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
const timeout = setTimeout(() => {
|
||||
observer.disconnect();
|
||||
resolve({ lcp: 0, fid: 0, cls: 0 }); // Default values if timeout
|
||||
}, 10000); // 10 second timeout
|
||||
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
const entries = list.getEntries();
|
||||
const metrics: any = {};
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.name === "LCP") {
|
||||
metrics.lcp = entry.startTime;
|
||||
} else if (entry.name === "FID") {
|
||||
metrics.fid = entry.processingStart - entry.startTime;
|
||||
} else if (entry.name === "CLS") {
|
||||
metrics.cls = entry.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(metrics).length === 3) {
|
||||
clearTimeout(timeout);
|
||||
const coreWebVitals = (await page.evaluate(() => {
|
||||
return new Promise<{ lcp: number; fid: number; cls: number }>(
|
||||
(resolve) => {
|
||||
const timeout = setTimeout(() => {
|
||||
observer.disconnect();
|
||||
resolve(metrics);
|
||||
}
|
||||
});
|
||||
resolve({ lcp: 0, fid: 0, cls: 0 }); // Default values if timeout
|
||||
}, 10000); // 10 second timeout
|
||||
|
||||
observer.observe({
|
||||
entryTypes: [
|
||||
"largest-contentful-paint",
|
||||
"first-input",
|
||||
"layout-shift",
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
const entries = list.getEntries();
|
||||
const metrics: { lcp?: number; fid?: number; cls?: number } = {};
|
||||
|
||||
for (const entry of entries) {
|
||||
const e = entry as any;
|
||||
if (
|
||||
e.name === "LCP" ||
|
||||
e.entryType === "largest-contentful-paint"
|
||||
) {
|
||||
metrics.lcp = e.startTime ?? 0;
|
||||
} else if (e.name === "FID" || e.entryType === "first-input") {
|
||||
metrics.fid = (e.processingStart ?? 0) - (e.startTime ?? 0);
|
||||
} else if (e.name === "CLS" || e.entryType === "layout-shift") {
|
||||
metrics.cls = e.value ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
metrics.lcp !== undefined &&
|
||||
metrics.fid !== undefined &&
|
||||
metrics.cls !== undefined
|
||||
) {
|
||||
clearTimeout(timeout);
|
||||
observer.disconnect();
|
||||
resolve({
|
||||
lcp: metrics.lcp,
|
||||
fid: metrics.fid,
|
||||
cls: metrics.cls,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe({
|
||||
entryTypes: [
|
||||
"largest-contentful-paint",
|
||||
"first-input",
|
||||
"layout-shift",
|
||||
],
|
||||
});
|
||||
},
|
||||
);
|
||||
})) as { lcp: number; fid: number; cls: number };
|
||||
|
||||
// Assert Core Web Vitals are within acceptable ranges
|
||||
expect(coreWebVitals.lcp).toBeLessThan(
|
||||
@@ -251,7 +265,7 @@ test.describe("Performance Monitoring", () => {
|
||||
});
|
||||
|
||||
test("network request performance", async ({ page }) => {
|
||||
const requests = await performanceMonitor.monitorNetworkRequests();
|
||||
await performanceMonitor.monitorNetworkRequests();
|
||||
|
||||
await page.goto("/");
|
||||
await page.waitForLoadState("networkidle");
|
||||
@@ -327,7 +341,7 @@ test.describe("Performance Monitoring", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const result = await performanceMonitor.measurePageLoad("/");
|
||||
await performanceMonitor.measurePageLoad("/");
|
||||
|
||||
// This should trigger a performance regression warning
|
||||
const summary = performanceMonitor.getSummary();
|
||||
|
||||
@@ -14,7 +14,7 @@ describe("Layout Integration", () => {
|
||||
<div>
|
||||
<Header />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Check that CommunityRule branding appears in both header and footer
|
||||
@@ -30,19 +30,21 @@ describe("Layout Integration", () => {
|
||||
<div>
|
||||
<Header />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Header navigation items
|
||||
expect(
|
||||
screen.getAllByRole("menuitem", { name: "Navigate to Use cases page" })
|
||||
.length
|
||||
.length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("menuitem", { name: "Navigate to Learn page" }).length
|
||||
screen.getAllByRole("menuitem", { name: "Navigate to Learn page" })
|
||||
.length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("menuitem", { name: "Navigate to About page" }).length
|
||||
screen.getAllByRole("menuitem", { name: "Navigate to About page" })
|
||||
.length,
|
||||
).toBeGreaterThan(0);
|
||||
|
||||
// Footer navigation items (should be present in footer as well)
|
||||
@@ -96,23 +98,23 @@ describe("Layout Integration", () => {
|
||||
// Contact information
|
||||
expect(screen.getByText("medlab@colorado.edu")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("link", { name: "medlab@colorado.edu" })
|
||||
screen.getByRole("link", { name: "medlab@colorado.edu" }),
|
||||
).toHaveAttribute("href", "mailto:medlab@colorado.edu");
|
||||
|
||||
// Social media links
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Follow us on Bluesky" })
|
||||
screen.getByRole("link", { name: "Follow us on Bluesky" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Follow us on GitLab" })
|
||||
screen.getByRole("link", { name: "Follow us on GitLab" }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Legal links
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Privacy Policy" })
|
||||
screen.getByRole("link", { name: "Privacy Policy" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Terms of Service" })
|
||||
screen.getByRole("link", { name: "Terms of Service" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -138,7 +140,7 @@ describe("Layout Integration", () => {
|
||||
<div>
|
||||
<Header />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Header should have banner role
|
||||
@@ -159,7 +161,7 @@ describe("Layout Integration", () => {
|
||||
<div>
|
||||
<Header />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Header should have responsive navigation elements
|
||||
@@ -176,7 +178,7 @@ describe("Layout Integration", () => {
|
||||
<div>
|
||||
<Header />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Get all interactive elements
|
||||
@@ -199,7 +201,7 @@ describe("Layout Integration", () => {
|
||||
<div>
|
||||
<Header />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Header provides main navigation
|
||||
@@ -219,7 +221,7 @@ describe("Layout Integration", () => {
|
||||
<div>
|
||||
<Header />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Main navigation in header
|
||||
@@ -232,13 +234,13 @@ describe("Layout Integration", () => {
|
||||
(link) =>
|
||||
link.textContent?.includes("Use cases") ||
|
||||
link.textContent?.includes("Learn") ||
|
||||
link.textContent?.includes("About")
|
||||
link.textContent?.includes("About"),
|
||||
);
|
||||
expect(navigationLinks.length).toBeGreaterThan(0);
|
||||
|
||||
// Contact information in footer
|
||||
expect(
|
||||
screen.getByRole("link", { name: "medlab@colorado.edu" })
|
||||
screen.getByRole("link", { name: "medlab@colorado.edu" }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+15
-15
@@ -27,7 +27,7 @@ describe("Footer", () => {
|
||||
expect(schemaData.email).toBe("medlab@colorado.edu");
|
||||
expect(schemaData.url).toBe("https://communityrule.com");
|
||||
expect(schemaData.sameAs).toContain(
|
||||
"https://bsky.app/profile/medlabboulder"
|
||||
"https://bsky.app/profile/medlabboulder",
|
||||
);
|
||||
expect(schemaData.sameAs).toContain("https://gitlab.com/medlabboulder");
|
||||
});
|
||||
@@ -36,7 +36,7 @@ describe("Footer", () => {
|
||||
render(<Footer />);
|
||||
|
||||
expect(
|
||||
screen.getAllByText("Media Economies Design Lab").length
|
||||
screen.getAllByText("Media Economies Design Lab").length,
|
||||
).toBeGreaterThan(0);
|
||||
|
||||
const emailLinks = screen.getAllByRole("link", {
|
||||
@@ -86,13 +86,13 @@ describe("Footer", () => {
|
||||
render(<Footer />);
|
||||
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Use cases" }).length
|
||||
screen.getAllByRole("link", { name: "Use cases" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Learn" }).length
|
||||
screen.getAllByRole("link", { name: "Learn" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "About" }).length
|
||||
screen.getAllByRole("link", { name: "About" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -100,13 +100,13 @@ describe("Footer", () => {
|
||||
render(<Footer />);
|
||||
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Privacy Policy" }).length
|
||||
screen.getAllByRole("link", { name: "Privacy Policy" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Terms of Service" }).length
|
||||
screen.getAllByRole("link", { name: "Terms of Service" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Cookies Settings" }).length
|
||||
screen.getAllByRole("link", { name: "Cookies Settings" }).length,
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -114,7 +114,7 @@ describe("Footer", () => {
|
||||
render(<Footer />);
|
||||
|
||||
expect(screen.getAllByText("© All right reserved").length).toBeGreaterThan(
|
||||
0
|
||||
0,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ describe("Footer", () => {
|
||||
|
||||
// Check that logo containers exist for different breakpoints
|
||||
const logoContainers = document.querySelectorAll(
|
||||
'[class*="block sm:hidden"], [class*="hidden sm:block lg:hidden"], [class*="hidden lg:block"]'
|
||||
'[class*="block sm:hidden"], [class*="hidden sm:block lg:hidden"], [class*="hidden lg:block"]',
|
||||
);
|
||||
expect(logoContainers.length).toBeGreaterThan(0);
|
||||
});
|
||||
@@ -147,7 +147,7 @@ describe("Footer", () => {
|
||||
|
||||
// The Separator component should be rendered (it uses a div with border, not hr)
|
||||
const separator = document.querySelector(
|
||||
".bg-\\[var\\(--border-color-default-secondary\\)\\]"
|
||||
".bg-\\[var\\(--border-color-default-secondary\\)\\]",
|
||||
);
|
||||
expect(separator).toBeInTheDocument();
|
||||
});
|
||||
@@ -263,10 +263,10 @@ describe("Footer", () => {
|
||||
expect(emailLink).toHaveClass("focus:ring-2");
|
||||
expect(emailLink).toHaveClass("focus:ring-offset-2");
|
||||
expect(emailLink).toHaveClass(
|
||||
"focus:ring-[var(--color-content-default-primary)]"
|
||||
"focus:ring-[var(--color-content-default-primary)]",
|
||||
);
|
||||
expect(emailLink).toHaveClass(
|
||||
"focus:ring-offset-[var(--color-surface-default-primary)]"
|
||||
"focus:ring-offset-[var(--color-surface-default-primary)]",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -276,10 +276,10 @@ describe("Footer", () => {
|
||||
expect(link).toHaveClass("focus:ring-2");
|
||||
expect(link).toHaveClass("focus:ring-offset-2");
|
||||
expect(link).toHaveClass(
|
||||
"focus:ring-[var(--color-content-default-primary)]"
|
||||
"focus:ring-[var(--color-content-default-primary)]",
|
||||
);
|
||||
expect(link).toHaveClass(
|
||||
"focus:ring-offset-[var(--color-surface-default-primary)]"
|
||||
"focus:ring-offset-[var(--color-surface-default-primary)]",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user