mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-10-04 02:33:47 +10:00
test(e2e): scope imported table border geometry (#3476)
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# Imported-table raster CI fix
|
||||
|
||||
## Root cause
|
||||
|
||||
Hosted runs `34007560930` (PR #3471) and `34007788443` (PR #3472) failed only in
|
||||
`tests/e2e/specs/imported-table.spec.ts` with `horizontal: 18` instead of Plan 16's
|
||||
`horizontal: 17`; text and vertical checks passed.
|
||||
|
||||
The PDF operator dump from the failed hosted artifact showed 29 table path records matching the Plan 16 contract
|
||||
(17 horizontal, 12 vertical), followed by an unrelated `constructPath` `endPath` bbox:
|
||||
`[0, 19.65, 358.93, 20.65]`. Its stroke color was reported as `#cc00cc` only because the helper retained the
|
||||
last table stroke color. It was a later red section-divider fill/no-paint path, not an extra table border. The old
|
||||
helper classified every thin bbox after the last matching color state, so it counted this false positive.
|
||||
|
||||
The table's explicit width is stable at 300pt, while row height legitimately changes from 30pt to 31pt after the
|
||||
`Beta!` edit. The helper therefore scopes candidate paths by the fixture's 300pt horizontal grid envelope, not by a
|
||||
row-height tolerance. Missing or duplicated paths inside that envelope still change the exact 17/12 contract.
|
||||
|
||||
## Change
|
||||
|
||||
- Added `tests/e2e/fixtures/pdf-borders.ts` with deterministic `countTableBorderGeometry` filtering.
|
||||
- Updated browser/server PDF inspection in `tests/e2e/specs/imported-table.spec.ts` to use the helper.
|
||||
- Added `tests/e2e/fixtures/pdf-borders.test.ts`; regression proves old stale-color counting returns 2 horizontal
|
||||
paths while topology-scoped counting returns 1.
|
||||
|
||||
## Verification
|
||||
|
||||
- Intent skill inventory: 7 packages, 26 skills; no matching local skill for this E2E/PDF helper.
|
||||
- Focused helper regression: 1 file, 1 passed.
|
||||
- Dedicated imported-table E2E: 2 consecutive runs, each 1 passed; both exercise initial, unrelated-edit, and table-edit
|
||||
stages plus browser and server PDF exports.
|
||||
- Production build: 3/3 tasks successful.
|
||||
- Web typecheck via `rtk proxy pnpm --filter web typecheck`: passed (`tsgo --noEmit`).
|
||||
- Turbo boundaries: 1,443 files across 20 packages, no issues.
|
||||
- Targeted Biome: 3 files, no issues.
|
||||
- `git diff --check`: passed.
|
||||
|
||||
The root `pnpm typecheck` wrapper was also tried but invokes an incompatible `tsc` path and reports TS5096 for
|
||||
`allowImportingTsExtensions`; the package's documented `tsgo --noEmit` typecheck passes.
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { BorderPath } from "./pdf-borders";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { countTableBorderGeometry } from "./pdf-borders";
|
||||
|
||||
describe("table border geometry", () => {
|
||||
it("does not count a later path after stale magenta stroke state", () => {
|
||||
const paths: BorderPath[] = [
|
||||
{ color: "#cc00cc", bounds: [0, 0, 100, 1] },
|
||||
{ color: "#cc00cc", bounds: [0, 19.65, 358.93, 20.65] },
|
||||
];
|
||||
const oldHorizontal = paths.filter(({ color, bounds: [x0, y0, x1, y1] }) => {
|
||||
const width = Math.abs((x1 ?? 0) - (x0 ?? 0));
|
||||
const height = Math.abs((y1 ?? 0) - (y0 ?? 0));
|
||||
return color === "#cc00cc" && height > 0 && height <= 1.01 && width > height;
|
||||
}).length;
|
||||
|
||||
expect(oldHorizontal).toBe(2);
|
||||
expect(countTableBorderGeometry(paths)).toEqual({ horizontal: 1, vertical: 0 });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
export type BorderPath = {
|
||||
color: string;
|
||||
bounds: readonly number[];
|
||||
};
|
||||
|
||||
export type BorderGeometry = {
|
||||
horizontal: number;
|
||||
vertical: number;
|
||||
};
|
||||
|
||||
// The imported-table fixture is explicitly 300pt wide. Row height can change when a cell is edited,
|
||||
// so use width as stable topology while excluding unrelated paths that inherit the table's stroke color.
|
||||
const TABLE_GRID_MAX_X = 300;
|
||||
|
||||
const isInsideTableWidth = (bounds: readonly number[]) => {
|
||||
const [x0, y0, x1, y1] = bounds;
|
||||
if (![x0, y0, x1, y1].every((value) => Number.isFinite(value))) return false;
|
||||
return Math.min(x0 ?? 0, x1 ?? 0) >= 0 && Math.max(x0 ?? 0, x1 ?? 0) <= TABLE_GRID_MAX_X;
|
||||
};
|
||||
|
||||
export function countTableBorderGeometry(paths: readonly BorderPath[]): BorderGeometry {
|
||||
let horizontal = 0;
|
||||
let vertical = 0;
|
||||
|
||||
for (const path of paths) {
|
||||
if (path.color !== "#cc00cc" || !isInsideTableWidth(path.bounds)) continue;
|
||||
const [x0, y0, x1, y1] = path.bounds;
|
||||
const width = Math.abs((x1 ?? 0) - (x0 ?? 0));
|
||||
const height = Math.abs((y1 ?? 0) - (y0 ?? 0));
|
||||
if (height > 0 && height <= 1.01 && width > height) horizontal++;
|
||||
if (width > 0 && width <= 1.01 && height > width) vertical++;
|
||||
}
|
||||
|
||||
return { horizontal, vertical };
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { readFile, writeFile } from "node:fs/promises";
|
||||
import { createRequire } from "node:module";
|
||||
import { Pool } from "pg";
|
||||
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
|
||||
import { countTableBorderGeometry } from "../fixtures/pdf-borders";
|
||||
import { ACTIVE_PREVIEW_PAGE_SELECTOR } from "../fixtures/preview";
|
||||
import { openSidebarSection } from "../fixtures/resume";
|
||||
import { expect, test } from "../fixtures/test";
|
||||
@@ -59,17 +60,17 @@ async function inspectPdf(bytes: Uint8Array) {
|
||||
const text = (await page.getTextContent()).items.flatMap((item: { str?: string }) => item.str ?? []);
|
||||
const operators = await page.getOperatorList();
|
||||
let stroke = "";
|
||||
let horizontal = 0;
|
||||
let vertical = 0;
|
||||
const borderPaths = [];
|
||||
for (const [index, fn] of operators.fnArray.entries()) {
|
||||
if (fn === OPS.setStrokeRGBColor) stroke = operators.argsArray[index][0];
|
||||
if (fn !== OPS.constructPath || stroke !== "#cc00cc") continue;
|
||||
if (fn !== OPS.constructPath) continue;
|
||||
const bounds = operators.argsArray[index][2] as ArrayLike<number>;
|
||||
const width = Math.abs((bounds[2] ?? 0) - (bounds[0] ?? 0));
|
||||
const height = Math.abs((bounds[3] ?? 0) - (bounds[1] ?? 0));
|
||||
if (height > 0 && height <= 1.01 && width > height) horizontal++;
|
||||
if (width > 0 && width <= 1.01 && height > width) vertical++;
|
||||
borderPaths.push({
|
||||
color: stroke,
|
||||
bounds: [bounds[0] ?? 0, bounds[1] ?? 0, bounds[2] ?? 0, bounds[3] ?? 0],
|
||||
});
|
||||
}
|
||||
const { horizontal, vertical } = countTableBorderGeometry(borderPaths);
|
||||
return { text, horizontal, vertical };
|
||||
} finally {
|
||||
await loading.destroy();
|
||||
|
||||
Reference in New Issue
Block a user