mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
e23f0e285e
`snapshot` gains an optional `cropOn: <selector>` — diff one element's
region instead of the whole screen:
`- snapshot: { name: cart-total, cropOn: "Order summary" }`
- The selector resolves like a directive target: settled tree,
auto-wait, the standard
not-found failure. Selector-only — no point form (a point has no extent
to crop to).
- The frame resolves **before** the capture, and the **cropped** image
is what gets
compared, stored as the baseline, and reported as the `current`
artifact. The pixel
rect is the normalized frame × capture size; the crop is a pngjs
`bitblt` written to
a swept scratch dir and registered only when a failure returns it.
- The baseline key stays on the **full** capture's WxH (device-class
identity), so the
previously unreachable `dimensionMismatch` guard becomes load-bearing:
an element that
grew or shrank fails with "nothing was compared" plus a
crop-fixed-size-containers
hint. Deliberately strict — a 1px layout drift fails on dimensions, not
content (the
same tradeoff as Playwright element screenshots).
- A tree-source outage while resolving `cropOn` errors the step instead
of degrading to
a full-screen compare against a cropped baseline.
- No tool-schema changes; `snapshotKey` and `--output` behavior ride
along unchanged.
Tests: parse/serialize round-trip + rejection cases, and runSnapshot
coverage with real
PNGs (crop dims, key vs. content, artifact retention/sweep, unresolved
selector, abort,
size-drift message, sub-pixel region).
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import { describe, it, expect, vi } from "vitest";
|
|
import { createFlowTestHarness } from "./harness";
|
|
import { runSnapshot } from "../../src/tools/flows/flow-visual";
|
|
|
|
// Mock ONLY runSnapshot: these tests pin the YAML-to-execution join in
|
|
// flow-run's snapshot arm (the single line threading the parsed step into
|
|
// runSnapshot's opts), which the flow-visual suite — calling runSnapshot
|
|
// directly with hand-built opts — cannot see. Dropping `cropOn: step.cropOn`
|
|
// there would keep every other test green while a declared crop silently ran
|
|
// as a full-screen snapshot.
|
|
vi.mock("../../src/tools/flows/flow-visual", async (importOriginal) => ({
|
|
...(await importOriginal<typeof import("../../src/tools/flows/flow-visual")>()),
|
|
runSnapshot: vi.fn(),
|
|
}));
|
|
|
|
const { writeFlow, run } = createFlowTestHarness({
|
|
tempDirectoryPrefix: "flow-snapshot-step-",
|
|
reset: () => {
|
|
vi.mocked(runSnapshot).mockReset();
|
|
vi.mocked(runSnapshot).mockResolvedValue({
|
|
status: "pass",
|
|
reason: "diff 0.00% ≤ 0.5% (row__ios-390x844.png)",
|
|
});
|
|
},
|
|
});
|
|
|
|
describe("snapshot step wiring", () => {
|
|
it("threads the parsed step — name, maxMismatch, cropOn — into runSnapshot", async () => {
|
|
await writeFlow("crop", {
|
|
executionPrerequisite: "",
|
|
steps: [{ kind: "snapshot", name: "row", maxMismatch: 1.5, cropOn: { identifier: "hdr" } }],
|
|
});
|
|
|
|
const result = await run("crop");
|
|
|
|
expect(result.steps).toEqual([expect.objectContaining({ status: "pass" })]);
|
|
expect(vi.mocked(runSnapshot)).toHaveBeenCalledWith(
|
|
expect.anything(),
|
|
expect.objectContaining({
|
|
name: "row",
|
|
maxMismatch: 1.5,
|
|
cropOn: expect.objectContaining({ identifier: "hdr" }),
|
|
})
|
|
);
|
|
});
|
|
|
|
it("passes no cropOn for a plain snapshot step", async () => {
|
|
await writeFlow("plain", {
|
|
executionPrerequisite: "",
|
|
steps: [{ kind: "snapshot", name: "home" }],
|
|
});
|
|
|
|
await run("plain");
|
|
|
|
expect(vi.mocked(runSnapshot)).toHaveBeenCalledWith(
|
|
expect.anything(),
|
|
expect.objectContaining({ name: "home", cropOn: undefined })
|
|
);
|
|
});
|
|
});
|