Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions packages/cli/src/commands/check.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,48 @@ describe("check pipeline", () => {
expect(browser).toHaveBeenCalledTimes(1);
});

// An unreadable sidecar used to return before the browser opened, so Layout/Runtime/Contrast
// printed "0 errors" without having looked — an all-clear the same composition contradicts.
it("still audits layout when the motion sidecar is invalid", async () => {
const motion: MotionSpecResolution = {
kind: "invalid",
path: "/project/index.motion.json",
message: 'assertions[0] (staysInFrame): "selector" must be a non-empty string',
};
const driver = fakeDriver({
collectLayout: vi.fn(async (time: number) => [layoutIssue("error", { time })]),
});
const { report, browser } = await runScenario(driver, {}, { motion });

expect(browser).toHaveBeenCalledTimes(1);
expect(report.layout.findings.length).toBeGreaterThan(0);
expect(report.motion.findings).toEqual([
expect.objectContaining({ code: "motion_spec_invalid", severity: "error" }),
]);
// A JSON consumer sees the spec was found but produced nothing sampleable.
expect(report.motion).toMatchObject({
enabled: true,
specPath: "/project/index.motion.json",
samples: 0,
});
expect(report.ok).toBe(false);
});

// Guards the new path rather than the old bug: now that the browser opens for an invalid sidecar,
// deleting `planMotionSampling`'s `kind !== "valid"` guard would crash on `motion.spec`.
it("does not sample motion for an invalid sidecar", async () => {
const motion: MotionSpecResolution = {
kind: "invalid",
path: "/project/index.motion.json",
message: "version 2 is not supported",
};
const driver = fakeDriver();
const { report } = await runScenario(driver, {}, { motion });

expect(report.motion.samples).toBe(0);
expect(driver.collectMotionFrame).not.toHaveBeenCalled();
});

it("reports a failing appearsBy sidecar as motion_appears_late", async () => {
const motion: MotionSpecResolution = {
kind: "valid",
Expand Down
25 changes: 15 additions & 10 deletions packages/cli/src/utils/checkPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1063,15 +1063,20 @@ export async function runCheckPipeline(
}

const motion = dependencies.resolveMotionSpec(project.dir);
if (motion.kind === "invalid") {
const finding = findingAtRoot(
"motion_spec_invalid",
"error",
motion.message,
relative(project.dir, motion.path) || "index.motion.json",
);
return buildReport(options, lint, emptyBrowserResult(), motion, [finding], []);
}
// An unreadable sidecar only invalidates the motion stage: layout, runtime and contrast never read
// it. `planMotionSampling` declines to sample anything but a valid spec, so the audit runs as usual
// and the parse error rides along as a motion finding.
const specFindings =
motion.kind === "invalid"
? [
findingAtRoot(
"motion_spec_invalid",
"error",
motion.message,
relative(project.dir, motion.path) || "index.motion.json",
),
]
: [];

let browser: CheckBrowserResult;
try {
Expand All @@ -1084,7 +1089,7 @@ export async function runCheckPipeline(
const snapshotFiles = options.snapshots
? await writeContrastSnapshots(dependencies, project.dir, browser)
: [];
const report = buildReport(options, lint, browser, motion, [], snapshotFiles);
const report = buildReport(options, lint, browser, motion, specFindings, snapshotFiles);
return options.snapshots
? await withFindingCrops(dependencies, project, options, report)
: report;
Expand Down
Loading