FN-8750: redesign resolved GitHub issues table
Improve the resolved GitHub issues table across desktop, tablet, and mobile layouts. - Add responsive table styling with semantic links and readable metadata. - Add table hooks and regression coverage for layout and token use. - Capture desktop and mobile layout smoke screenshots. Files changed: ...mmand-center-css-token-canonicalization.test.ts | 15 ++ .../components/command-center/areas/GithubArea.tsx | 37 +++-- .../areas/__tests__/areas.github-signals.test.tsx | 27 ++-- .../app/components/command-center/areas/areas.css | 151 +++++++++++++++++++++ .../dashboard/scripts/browser-layout-smoke.mjs | 120 +++++++++++++++- screenshots/fn-8750-resolved-github-desktop.png | 3 + screenshots/fn-8750-resolved-github-mobile.png | 3 + 7 files changed, 333 insertions(+), 23 deletions(-) Fusion-Task-Id: FN-8750 Fusion-Task-Lineage: b229bad6-7d32-4a04-9681-c4184c46c015 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -3,6 +3,7 @@ import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const COMMAND_CENTER_ROOT = path.resolve(__dirname, "..");
|
||||
const AREAS_CSS_PATH = path.join(COMMAND_CENTER_ROOT, "areas", "areas.css");
|
||||
|
||||
function collectCssFiles(dir: string): string[] {
|
||||
const out: string[] = [];
|
||||
@@ -37,4 +38,18 @@ describe("Command Center CSS token canonicalization", () => {
|
||||
expect(chartsCss).toContain("var(--accent)");
|
||||
expect(chartsCss).toContain("var(--text)");
|
||||
});
|
||||
|
||||
it("scopes the resolved GitHub table contract to tokenized responsive selectors", () => {
|
||||
const areasCss = readFileSync(AREAS_CSS_PATH, "utf8");
|
||||
const resolvedTableCss = areasCss.match(/\.cc-github-resolved-table-wrap[\s\S]*?(?=\.cc-sort-caret)/)?.[0];
|
||||
|
||||
expect(resolvedTableCss).toBeTruthy();
|
||||
expect(resolvedTableCss).toContain(".cc-github-resolved-table");
|
||||
expect(resolvedTableCss).toContain("table-layout: fixed");
|
||||
expect(resolvedTableCss).toContain("overflow-wrap: anywhere");
|
||||
expect(resolvedTableCss).toContain("var(--accent)");
|
||||
expect(resolvedTableCss).toContain("var(--focus-ring)");
|
||||
expect(resolvedTableCss).toContain("@media (max-width: 768px)");
|
||||
expect(resolvedTableCss).not.toMatch(/\b\d+px\s*;|#[0-9a-f]{3,8}\b|rgba\(/i);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,9 @@ The GitHub Command Center area visualizes only locally persisted task-store data
|
||||
|
||||
FNXC:CommandCenterGithub 2026-06-21-03:28:
|
||||
FN-6722 adds a resolved-issues detail list so operators can see which imported GitHub source issues were completed in the selected range. The UI must render only rows returned by the local task-store analytics endpoint, link out only when `sourceIssueUrl` exists, and mark `updatedAt` fallback dates as approximate.
|
||||
|
||||
FNXC:CommandCenterGithub 2026-08-03-04:08:
|
||||
FN-8750 gives the resolved table its own responsive visual contract. Semantic outbound links retain their safe attributes while using the dashboard accent/focus treatment; long task titles wrap independently from compact task IDs and resolution metadata at desktop, tablet, and mobile widths.
|
||||
*/
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -269,8 +272,8 @@ export function GithubArea({ range, projectId }: { range: DateRange; projectId?:
|
||||
{hasResolvedIssues ? (
|
||||
<div className="cc-area-section" data-testid="cc-github-resolved">
|
||||
<h3 className="cc-area-section-title">{t("commandCenter.github.resolvedTitle", "Resolved issues")}</h3>
|
||||
<div className="cc-table-wrap">
|
||||
<table className="cc-table">
|
||||
<div className="cc-table-wrap cc-github-resolved-table-wrap" data-testid="cc-github-resolved-table-wrap">
|
||||
<table className="cc-table cc-github-resolved-table" data-testid="cc-github-resolved-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{t("commandCenter.github.resolvedIssue", "Issue")}</th>
|
||||
@@ -285,11 +288,13 @@ export function GithubArea({ range, projectId }: { range: DateRange; projectId?:
|
||||
issue.resolvedAt,
|
||||
t("commandCenter.github.resolvedAtUnknown", "Unknown"),
|
||||
);
|
||||
const hasTaskTitle = Boolean(issue.taskTitle);
|
||||
return (
|
||||
<tr key={issue.taskId}>
|
||||
<td>
|
||||
<td className="cc-github-resolved-issue-cell">
|
||||
{issue.url ? (
|
||||
<a
|
||||
className="cc-github-resolved-issue-link"
|
||||
href={issue.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@@ -298,20 +303,24 @@ export function GithubArea({ range, projectId }: { range: DateRange; projectId?:
|
||||
{issueRef}
|
||||
</a>
|
||||
) : (
|
||||
<span>{issueRef}</span>
|
||||
<span className="cc-github-resolved-issue-ref">{issueRef}</span>
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<span>{issue.taskTitle || issue.taskId}</span>{" "}
|
||||
<span className="cc-stat-sub">({issue.taskId})</span>
|
||||
<td className="cc-github-resolved-task-cell">
|
||||
<span className="cc-github-resolved-task">
|
||||
<span className="cc-github-resolved-task-title">{issue.taskTitle || issue.taskId}</span>
|
||||
{hasTaskTitle ? <span className="cc-stat-sub cc-github-resolved-task-id">{issue.taskId}</span> : null}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{resolvedAt}</span>{" "}
|
||||
{!issue.resolvedAtExact ? (
|
||||
<span className="cc-stat-sub">
|
||||
{t("commandCenter.github.resolvedApprox", "approx")}
|
||||
</span>
|
||||
) : null}
|
||||
<td className="cc-github-resolved-date-cell">
|
||||
<span className="cc-github-resolved-date">
|
||||
<span>{resolvedAt}</span>
|
||||
{!issue.resolvedAtExact ? (
|
||||
<span className="cc-stat-sub cc-github-resolved-date-approx">
|
||||
{t("commandCenter.github.resolvedApprox", "approx")}
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
@@ -114,14 +114,15 @@ describe("GithubArea", () => {
|
||||
expect(within(repoChart).getByLabelText("acme/alpha: 4 filed / 1 fixed")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders resolved issues with safe outbound links and approximation labels", async () => {
|
||||
it("renders long resolved content with safe links, title fallback, and exact or approximate metadata", async () => {
|
||||
const longTitle = "Resolve a deliberately long imported GitHub issue title without forcing the Command Center table beyond its responsive container";
|
||||
apiMock.mockResolvedValue({
|
||||
...githubFixture(),
|
||||
resolved: [
|
||||
{
|
||||
taskId: "FN-100",
|
||||
taskTitle: "Fix alpha crash",
|
||||
repo: "acme/alpha",
|
||||
taskTitle: longTitle,
|
||||
repo: "acme/a-deliberately-long-repository-reference",
|
||||
issueNumber: 123,
|
||||
url: "https://github.com/acme/alpha/issues/123",
|
||||
resolvedAt: "2026-06-10T12:34:56.000Z",
|
||||
@@ -129,7 +130,7 @@ describe("GithubArea", () => {
|
||||
},
|
||||
{
|
||||
taskId: "FN-101",
|
||||
taskTitle: "Patch unknown import",
|
||||
taskTitle: "",
|
||||
repo: "(unknown)",
|
||||
issueNumber: null,
|
||||
url: null,
|
||||
@@ -142,20 +143,30 @@ describe("GithubArea", () => {
|
||||
render(<GithubArea range={range7d} />);
|
||||
|
||||
const section = await screen.findByTestId("cc-github-resolved");
|
||||
const table = within(section).getByTestId("cc-github-resolved-table");
|
||||
expect(section.textContent).toContain("Resolved issues");
|
||||
expect(section.textContent).toContain("acme/alpha#123");
|
||||
expect(section.textContent).toContain("Fix alpha crash");
|
||||
expect(section.textContent).toContain("acme/a-deliberately-long-repository-reference#123");
|
||||
expect(section.textContent).toContain(longTitle);
|
||||
expect(section.textContent).toContain("FN-100");
|
||||
expect(section.textContent).toContain("(unknown)");
|
||||
expect(section.textContent).toContain("Patch unknown import");
|
||||
expect(section.textContent).toContain("approx");
|
||||
expect(section.textContent).toContain("2026");
|
||||
expect(table.className).toContain("cc-github-resolved-table");
|
||||
|
||||
const linkedIssue = within(section).getByRole("link", { name: "Open GitHub issue acme/alpha#123" });
|
||||
const linkedIssue = within(section).getByRole("link", { name: "Open GitHub issue acme/a-deliberately-long-repository-reference#123" });
|
||||
expect(linkedIssue.className).toContain("cc-github-resolved-issue-link");
|
||||
expect(linkedIssue.getAttribute("href")).toBe("https://github.com/acme/alpha/issues/123");
|
||||
expect(linkedIssue.getAttribute("target")).toBe("_blank");
|
||||
expect(linkedIssue.getAttribute("rel")).toBe("noopener noreferrer");
|
||||
expect(within(section).queryByRole("link", { name: /unknown/i })).toBeNull();
|
||||
|
||||
const title = within(section).getByText(longTitle);
|
||||
expect(title.className).toContain("cc-github-resolved-task-title");
|
||||
expect(within(section).getByText("FN-100").className).toContain("cc-github-resolved-task-id");
|
||||
const fallback = within(section).getByText("FN-101");
|
||||
expect(fallback.className).toContain("cc-github-resolved-task-title");
|
||||
expect(within(section).queryByText("(FN-101)")).toBeNull();
|
||||
expect(within(section).getByText("approx").className).toContain("cc-github-resolved-date-approx");
|
||||
});
|
||||
|
||||
it("omits the resolved issues section for an empty resolved list", async () => {
|
||||
|
||||
@@ -174,6 +174,157 @@ FN-6680 keeps table-heavy chart areas on the same --border-width/--border-subtle
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:CommandCenterGithub 2026-08-03-04:08:
|
||||
FN-8750 scopes the resolved-issues redesign below its GitHub-specific classes so Team, Workflow, and Tokens retain their compact analytics-table contract. A fixed table layout and wrapping task title preserve readable rows without page-level overflow; issue links stay visibly actionable with the shared accent and focus ring in every theme.
|
||||
*/
|
||||
.cc-github-resolved-table-wrap {
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.cc-github-resolved-table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th,
|
||||
.cc-github-resolved-table td {
|
||||
border-color: var(--border-subtle);
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table thead th {
|
||||
background: var(--surface-2);
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th:first-child,
|
||||
.cc-github-resolved-table td:first-child {
|
||||
inline-size: 28%;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th:nth-child(2),
|
||||
.cc-github-resolved-table td:nth-child(2) {
|
||||
inline-size: 48%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th:last-child,
|
||||
.cc-github-resolved-table td:last-child {
|
||||
inline-size: 24%;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table tbody tr {
|
||||
cursor: default;
|
||||
transition: background-color var(--duration-fast) ease;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table tbody tr:hover {
|
||||
background: color-mix(in srgb, var(--accent) 8%, var(--surface-1));
|
||||
}
|
||||
|
||||
.cc-github-resolved-table tbody tr:last-child td {
|
||||
border-block-end: 0;
|
||||
}
|
||||
|
||||
.cc-github-resolved-issue-cell,
|
||||
.cc-github-resolved-task-cell,
|
||||
.cc-github-resolved-date-cell {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.cc-github-resolved-issue-link {
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
overflow-wrap: anywhere;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: color-mix(in srgb, var(--accent) 55%, transparent);
|
||||
text-underline-offset: var(--space-xs);
|
||||
transition: color var(--duration-fast) ease, text-decoration-color var(--duration-fast) ease;
|
||||
}
|
||||
|
||||
.cc-github-resolved-issue-link:hover {
|
||||
color: var(--text);
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
|
||||
.cc-github-resolved-issue-link:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
|
||||
.cc-github-resolved-issue-ref {
|
||||
color: var(--text-muted);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.cc-github-resolved-task {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-xs);
|
||||
min-inline-size: 0;
|
||||
}
|
||||
|
||||
.cc-github-resolved-task-title {
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.cc-github-resolved-task-id {
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cc-github-resolved-date {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space-xs);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.cc-github-resolved-date-approx {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.cc-github-resolved-table th:first-child,
|
||||
.cc-github-resolved-table td:first-child {
|
||||
inline-size: 32%;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th:nth-child(2),
|
||||
.cc-github-resolved-table td:nth-child(2) {
|
||||
inline-size: 44%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cc-github-resolved-table th,
|
||||
.cc-github-resolved-table td {
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th:first-child,
|
||||
.cc-github-resolved-table td:first-child {
|
||||
inline-size: 31%;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th:nth-child(2),
|
||||
.cc-github-resolved-table td:nth-child(2) {
|
||||
inline-size: 45%;
|
||||
}
|
||||
|
||||
.cc-github-resolved-table th:last-child,
|
||||
.cc-github-resolved-table td:last-child {
|
||||
inline-size: 24%;
|
||||
}
|
||||
|
||||
.cc-github-resolved-date {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.cc-sort-caret {
|
||||
margin-inline-start: var(--space-xs);
|
||||
font-size: 0.7em;
|
||||
|
||||
@@ -24,6 +24,9 @@ const gitManagerAfterMobileScreenshotPath = process.env.FUSION_GIT_MANAGER_AFTER
|
||||
const gitHubImportBeforeMobileScreenshotPath = process.env.FUSION_GITHUB_IMPORT_BEFORE_MOBILE_SCREENSHOT;
|
||||
const gitHubImportAfterMobileScreenshotPath = process.env.FUSION_GITHUB_IMPORT_AFTER_MOBILE_SCREENSHOT;
|
||||
const gitHubImportAfterShortScreenshotPath = process.env.FUSION_GITHUB_IMPORT_AFTER_SHORT_SCREENSHOT;
|
||||
const resolvedGithubDesktopScreenshotPath = process.env.FUSION_RESOLVED_GITHUB_DESKTOP_SCREENSHOT;
|
||||
const resolvedGithubMobileScreenshotPath = process.env.FUSION_RESOLVED_GITHUB_MOBILE_SCREENSHOT;
|
||||
const smokeTheme = process.env.FUSION_BROWSER_SMOKE_THEME === "light" ? "light" : "dark";
|
||||
|
||||
function log(message) {
|
||||
console.log(`[dashboard-browser-smoke] ${message}`);
|
||||
@@ -205,6 +208,41 @@ export function createSmokeHtml() {
|
||||
Blink must measure the production responsive contract at each supported phone width because jsdom
|
||||
cannot detect wrapping, flex-track shrinkage, overflow, or touch-target geometry.
|
||||
*/
|
||||
/*
|
||||
FNXC:CommandCenterGithub 2026-08-03-04:08:
|
||||
FN-8750 needs a real-browser, production-CSS fixture because jsdom cannot measure fixed-table tracks,
|
||||
long-word wrapping, or page overflow. The fixture mirrors URL/no-URL, exact/approximate, and title-fallback rows
|
||||
so the desktop and mobile proof captures show the same resilient resolved-issue contract operators use.
|
||||
*/
|
||||
const resolvedGithubTableFixture = `
|
||||
<section class="command-center" data-smoke="github-resolved-table" aria-label="Resolved GitHub issues">
|
||||
<div class="cc-tabpanel" role="tabpanel">
|
||||
<section class="cc-area">
|
||||
<div class="cc-area-section">
|
||||
<h3 class="cc-area-section-title">Resolved issues</h3>
|
||||
<div class="cc-table-wrap cc-github-resolved-table-wrap">
|
||||
<table class="cc-table cc-github-resolved-table">
|
||||
<thead><tr><th scope="col">Issue</th><th scope="col">Resolving task</th><th scope="col">Resolved at</th></tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="cc-github-resolved-issue-cell"><a class="cc-github-resolved-issue-link" href="https://github.com/acme/a-deliberately-long-repository-reference/issues/123" target="_blank" rel="noopener noreferrer">acme/a-deliberately-long-repository-reference#123</a></td>
|
||||
<td class="cc-github-resolved-task-cell"><span class="cc-github-resolved-task"><span class="cc-github-resolved-task-title">Resolve a deliberately long imported GitHub issue title without forcing the Command Center table beyond its responsive container</span><span class="cc-stat-sub cc-github-resolved-task-id">FN-100</span></span></td>
|
||||
<td class="cc-github-resolved-date-cell"><span class="cc-github-resolved-date"><span>6/10/2026, 12:34 PM</span></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="cc-github-resolved-issue-cell"><span class="cc-github-resolved-issue-ref">(unknown)</span></td>
|
||||
<td class="cc-github-resolved-task-cell"><span class="cc-github-resolved-task"><span class="cc-github-resolved-task-title">FN-101</span></span></td>
|
||||
<td class="cc-github-resolved-date-cell"><span class="cc-github-resolved-date"><span>6/09/2026, 8:00 AM</span><span class="cc-stat-sub cc-github-resolved-date-approx">approx</span></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
||||
const githubImportMobileActionFixture = `
|
||||
<section data-smoke="github-import-mobile-actions" aria-label="GitHub issue detail actions">
|
||||
<div class="github-import-detail-actions" data-testid="github-import-detail-actions">
|
||||
@@ -293,7 +331,7 @@ export function createSmokeHtml() {
|
||||
<title>Fusion dashboard browser smoke</title>
|
||||
<link rel="stylesheet" href="/app.css" />
|
||||
</head>
|
||||
<body data-theme="dark">
|
||||
<body data-theme="${smokeTheme}">
|
||||
<div id="root">
|
||||
${gitManagerFixtures}
|
||||
${gitHubImportFixtures}
|
||||
@@ -375,6 +413,7 @@ export function createSmokeHtml() {
|
||||
</section>
|
||||
|
||||
${githubImportMobileActionFixture}
|
||||
${resolvedGithubTableFixture}
|
||||
|
||||
<footer class="executor-status-bar">
|
||||
<div class="executor-status-bar__segment">
|
||||
@@ -951,6 +990,31 @@ async function evaluate(page, expression) {
|
||||
return result.result.value;
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:CommandCenterGithub 2026-08-03-04:32:
|
||||
FN-8750 proof captures must preserve the production fixture layout so overflow checks at later viewports
|
||||
measure the table rather than a temporary overlay. Render a disposable clone in an isolated host,
|
||||
which keeps unrelated dashboard UI out of the artifact without mutating the measured fixture.
|
||||
*/
|
||||
async function captureFixtureScreenshot(page, selector, outputPath) {
|
||||
await evaluate(page, `(async () => {
|
||||
const fixture = document.querySelector(${JSON.stringify(selector)});
|
||||
const host = document.createElement("div");
|
||||
host.dataset.smokeCaptureHost = "true";
|
||||
host.style.cssText = "position: fixed; inset: 0; z-index: 9999; display: flex; overflow: auto; background: var(--bg);";
|
||||
const clone = fixture.cloneNode(true);
|
||||
host.append(clone);
|
||||
document.body.append(host);
|
||||
await new Promise(requestAnimationFrame);
|
||||
})()`);
|
||||
try {
|
||||
const screenshot = await page.send("Page.captureScreenshot", { format: "png" });
|
||||
await writeFile(outputPath, Buffer.from(screenshot.data, "base64"));
|
||||
} finally {
|
||||
await evaluate(page, "document.querySelector('[data-smoke-capture-host]').remove()");
|
||||
}
|
||||
}
|
||||
|
||||
function assertSmokeResult(name, passed, details) {
|
||||
if (!passed) {
|
||||
fail(`${name} failed: ${details}`);
|
||||
@@ -1067,6 +1131,43 @@ async function runSmokeChecks(page, pageUrl) {
|
||||
return { viewportWidth, controls, workerToggleCount: worker.querySelectorAll('[data-smoke="agent-heartbeat-toggle"]').length, fixtureOverflow: fixture.scrollWidth - fixture.clientWidth, documentOverflow: document.documentElement.scrollWidth - viewportWidth };
|
||||
})()`);
|
||||
|
||||
const collectResolvedGithubTableLayout = () => evaluate(page, `(() => {
|
||||
const fixture = document.querySelector('[data-smoke="github-resolved-table"]');
|
||||
const table = fixture.querySelector('.cc-github-resolved-table');
|
||||
const title = fixture.querySelector('.cc-github-resolved-task-title');
|
||||
const link = fixture.querySelector('.cc-github-resolved-issue-link');
|
||||
const fixtureRect = fixture.getBoundingClientRect();
|
||||
const titleRect = title.getBoundingClientRect();
|
||||
const linkStyle = getComputedStyle(link);
|
||||
return {
|
||||
documentOverflow: document.documentElement.scrollWidth - window.innerWidth,
|
||||
fixtureOverflow: fixture.scrollWidth - fixture.clientWidth,
|
||||
tableOverflow: table.scrollWidth - table.clientWidth,
|
||||
titleHeight: titleRect.height,
|
||||
titleWidth: titleRect.width,
|
||||
fixtureWidth: fixtureRect.width,
|
||||
linkColor: linkStyle.color,
|
||||
linkTextDecoration: linkStyle.textDecorationLine,
|
||||
};
|
||||
})()`);
|
||||
|
||||
const mobileResolvedGithubTableLayout = await collectResolvedGithubTableLayout();
|
||||
assertSmokeResult(
|
||||
"resolved GitHub table wraps long content without mobile page overflow",
|
||||
mobileResolvedGithubTableLayout.documentOverflow <= 1
|
||||
&& mobileResolvedGithubTableLayout.fixtureOverflow <= 1
|
||||
&& mobileResolvedGithubTableLayout.tableOverflow <= 1
|
||||
&& mobileResolvedGithubTableLayout.titleHeight > 0
|
||||
&& mobileResolvedGithubTableLayout.titleWidth <= mobileResolvedGithubTableLayout.fixtureWidth
|
||||
&& mobileResolvedGithubTableLayout.linkColor !== ""
|
||||
&& mobileResolvedGithubTableLayout.linkTextDecoration.includes("underline"),
|
||||
JSON.stringify(mobileResolvedGithubTableLayout),
|
||||
);
|
||||
if (resolvedGithubMobileScreenshotPath) {
|
||||
await captureFixtureScreenshot(page, '[data-smoke="github-resolved-table"]', resolvedGithubMobileScreenshotPath);
|
||||
log(`saved resolved GitHub mobile screenshot to ${resolvedGithubMobileScreenshotPath}`);
|
||||
}
|
||||
|
||||
const mobileAgentHeartbeatLayout = await collectAgentHeartbeatControlLayout();
|
||||
assertSmokeResult(
|
||||
"agent heartbeat controls stay visible on mobile and omit ephemeral shells",
|
||||
@@ -1687,6 +1788,23 @@ async function runSmokeChecks(page, pageUrl) {
|
||||
mobile: false,
|
||||
});
|
||||
await evaluate(page, "document.fonts ? document.fonts.ready.then(() => true) : true");
|
||||
const desktopResolvedGithubTableLayout = await collectResolvedGithubTableLayout();
|
||||
assertSmokeResult(
|
||||
"resolved GitHub table keeps readable desktop columns without overflow",
|
||||
desktopResolvedGithubTableLayout.documentOverflow <= 1
|
||||
&& desktopResolvedGithubTableLayout.fixtureOverflow <= 1
|
||||
&& desktopResolvedGithubTableLayout.tableOverflow <= 1
|
||||
&& desktopResolvedGithubTableLayout.titleHeight > 0
|
||||
&& desktopResolvedGithubTableLayout.titleWidth <= desktopResolvedGithubTableLayout.fixtureWidth
|
||||
&& desktopResolvedGithubTableLayout.linkColor !== ""
|
||||
&& desktopResolvedGithubTableLayout.linkTextDecoration.includes("underline"),
|
||||
JSON.stringify(desktopResolvedGithubTableLayout),
|
||||
);
|
||||
if (resolvedGithubDesktopScreenshotPath) {
|
||||
await captureFixtureScreenshot(page, '[data-smoke="github-resolved-table"]', resolvedGithubDesktopScreenshotPath);
|
||||
log(`saved resolved GitHub desktop screenshot to ${resolvedGithubDesktopScreenshotPath}`);
|
||||
}
|
||||
|
||||
const desktopAgentHeartbeatLayout = await collectAgentHeartbeatControlLayout();
|
||||
assertSmokeResult(
|
||||
"agent heartbeat controls stay visible on desktop and omit ephemeral shells",
|
||||
|
||||
BIN
screenshots/fn-8750-resolved-github-desktop.png
LFS
Normal file
BIN
screenshots/fn-8750-resolved-github-desktop.png
LFS
Normal file
Binary file not shown.
BIN
screenshots/fn-8750-resolved-github-mobile.png
LFS
Normal file
BIN
screenshots/fn-8750-resolved-github-mobile.png
LFS
Normal file
Binary file not shown.
Reference in New Issue
Block a user