import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import {
  parseTestCasesFromDoc,
  parseItDescriptionsFromTest,
  parseScenarioPatternsFromDoc,
  parseDescribeBlocksFromSpec,
} from "../parse-doc-test-cases";
import {
  runModuleTestCaseSyncCheck,
  runAppTestCaseSyncCheck,
  runE2eSyncCheck,
  parseActorNamesFromFixture,
  runActorSyncCheck,
  runScreenPageSyncCheck,
  runSpecFixtureSyncCheck,
} from "./sync-check-tests";

describe("parseTestCasesFromDoc", () => {
  it("extracts test cases from ## Test Cases section", () => {
    const content = `# CreateProduct

## Error Scenarios

- **DUPLICATE_CODE**: A product with the same code already exists

## Test Cases

- returns error when code is empty
- creates product in DRAFT status
- passes custom fields through
`;
    const cases = parseTestCasesFromDoc(content);
    expect(cases).toEqual([
      "returns error when code is empty",
      "creates product in DRAFT status",
      "passes custom fields through",
    ]);
  });

  it("returns empty array when no Test Cases section", () => {
    const content = `# CreateProduct\n\n## Overview\n\nSome text.`;
    expect(parseTestCasesFromDoc(content)).toEqual([]);
  });

  it("stops at next ## heading", () => {
    const content = `## Test Cases

- case one
- case two

## Other Section

- not a test case
`;
    expect(parseTestCasesFromDoc(content)).toEqual(["case one", "case two"]);
  });
});

describe("parseItDescriptionsFromTest", () => {
  it("extracts it() descriptions from test file", () => {
    const content = `
describe("createProduct", () => {
  it("returns error when code is empty", async () => {});
  it("creates product in DRAFT status", async () => {});
  it('passes custom fields through', async () => {});
});`;
    const descriptions = parseItDescriptionsFromTest(content);
    expect(descriptions).toEqual([
      "returns error when code is empty",
      "creates product in DRAFT status",
      "passes custom fields through",
    ]);
  });

  it("returns empty array when no it() blocks", () => {
    expect(parseItDescriptionsFromTest("const x = 1;")).toEqual([]);
  });
});

describe("runModuleTestCaseSyncCheck", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-check-tc-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  it("reports missing-test-case when doc has case not in test", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n- validates input\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); });',
    );

    const errors = await runModuleTestCaseSyncCheck("modules", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-case",
        category: "command-test-case",
        expectedBasename: "validates input",
      }),
    );
  });

  it("reports extra-test-case when test has case not in doc", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); it("extra case", async () => {}); });',
    );

    const errors = await runModuleTestCaseSyncCheck("modules", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "extra-test-case",
        category: "command-test-case",
        expectedBasename: "extra case",
      }),
    );
  });

  it("returns 0 when doc test cases match test it() descriptions", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n- validates input\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); it("validates input", async () => {}); });',
    );

    const errors = await runModuleTestCaseSyncCheck("modules", tmpDir);
    const tcErrors = errors.filter(
      (e) => e.type === "missing-test-case" || e.type === "extra-test-case",
    );
    expect(tcErrors).toHaveLength(0);
  });

  it("reports missing-test-file when test file does not exist", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Test Cases\n\n- creates order\n- validates input\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    // No createOrder.test.ts file

    const errors = await runModuleTestCaseSyncCheck("modules", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-file",
        category: "command-test-case",
        expectedBasename: "createOrder.test.ts",
      }),
    );
  });

  it("skips test-case check when doc has no Test Cases section", async () => {
    const docDir = path.join(tmpDir, "modules", "foo", "docs", "command");
    const testDir = path.join(tmpDir, "modules", "foo", "command");
    fs.mkdirSync(docDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });

    fs.writeFileSync(
      path.join(docDir, "CreateOrder.md"),
      "# CreateOrder\n\n## Overview\n\nSome text.\n",
    );
    fs.writeFileSync(path.join(testDir, "createOrder.ts"), "export {}");
    fs.writeFileSync(
      path.join(testDir, "createOrder.test.ts"),
      'describe("createOrder", () => { it("creates order", async () => {}); });',
    );

    const errors = await runModuleTestCaseSyncCheck("modules", tmpDir);
    const tcErrors = errors.filter(
      (e) => e.type === "missing-test-case" || e.type === "extra-test-case",
    );
    expect(tcErrors).toHaveLength(0);
  });
});

describe("runAppTestCaseSyncCheck", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-check-story-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  function setupStoryFixture(storyName: string, storyContent: string, testContent: string) {
    const flow = "item-lifecycle";
    const storyDir = path.join(tmpDir, "my-app", "docs", "business-flow", flow, "story");
    const testDir = path.join(tmpDir, "my-app", "backend", "src", "tests", "story", flow);
    fs.mkdirSync(storyDir, { recursive: true });
    fs.mkdirSync(testDir, { recursive: true });
    fs.writeFileSync(path.join(storyDir, `${storyName}.md`), storyContent);
    fs.writeFileSync(path.join(testDir, `${storyName}.test.ts`), testContent);
  }

  it("reports missing-test-case when story doc has case not in test", async () => {
    setupStoryFixture(
      "admin--create-item",
      "# Create Item\n\n## Test Cases\n\n- creates item\n- validates input\n",
      'describe("admin--create-item", () => { it("creates item", async () => {}); });',
    );

    const errors = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-case",
        category: "story-test-case",
        expectedBasename: "validates input",
      }),
    );
  });

  it("reports extra-test-case when test has case not in story doc", async () => {
    setupStoryFixture(
      "admin--create-item",
      "# Create Item\n\n## Test Cases\n\n- creates item\n",
      'describe("admin--create-item", () => { it("creates item", async () => {}); it("extra case", async () => {}); });',
    );

    const errors = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "extra-test-case",
        category: "story-test-case",
        expectedBasename: "extra case",
      }),
    );
  });

  it("returns no errors when story doc and test match", async () => {
    setupStoryFixture(
      "admin--create-item",
      "# Create Item\n\n## Test Cases\n\n- creates item\n- validates input\n",
      'describe("admin--create-item", () => { it("creates item", async () => {}); it("validates input", async () => {}); });',
    );

    const errors = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("reports missing-test-file when story test file does not exist", async () => {
    const flow = "item-lifecycle";
    const storyDir = path.join(tmpDir, "my-app", "docs", "business-flow", flow, "story");
    fs.mkdirSync(storyDir, { recursive: true });
    // No test file created
    fs.writeFileSync(
      path.join(storyDir, "admin--create-item.md"),
      "# Create Item\n\n## Test Cases\n\n- creates item\n- validates input\n",
    );

    const errors = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-file",
        category: "story-test-case",
        expectedBasename: "admin--create-item.test.ts",
      }),
    );
  });

  it("skips when story doc has no Test Cases section", async () => {
    setupStoryFixture(
      "admin--view-items",
      "# View Items\n\n## Scenario Patterns\n\n- Browse items\n",
      'describe("admin--view-items", () => { it("some test", async () => {}); });',
    );

    const errors = await runAppTestCaseSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });
});

describe("parseScenarioPatternsFromDoc", () => {
  it("extracts patterns from ## Scenario Patterns section", () => {
    const content = `# Create Item

## Scenario Patterns

- Admin creates a new item in DRAFT status
- Admin creates an item with all optional fields

## Test Cases

- not a scenario
`;
    expect(parseScenarioPatternsFromDoc(content)).toEqual([
      "Admin creates a new item in DRAFT status",
      "Admin creates an item with all optional fields",
    ]);
  });

  it("returns empty array when no Scenario Patterns section", () => {
    expect(parseScenarioPatternsFromDoc("# Foo\n\n## Test Cases\n\n- bar\n")).toEqual([]);
  });
});

describe("parseDescribeBlocksFromSpec", () => {
  it("extracts describe blocks with their test names", () => {
    const content = `
describe("admin--create-item", () => {
  test("Admin creates a new item in DRAFT status", async () => {});
  test("Admin creates an item with all optional fields", async () => {});
});

describe("admin--activate-item", () => {
  test("Admin activates a DRAFT item to ACTIVE", async () => {});
});`;
    const blocks = parseDescribeBlocksFromSpec(content);
    expect(blocks.get("admin--create-item")).toEqual([
      "Admin creates a new item in DRAFT status",
      "Admin creates an item with all optional fields",
    ]);
    expect(blocks.get("admin--activate-item")).toEqual(["Admin activates a DRAFT item to ACTIVE"]);
  });

  it("returns empty map for file with no describe blocks", () => {
    expect(parseDescribeBlocksFromSpec("const x = 1;").size).toBe(0);
  });
});

describe("runE2eSyncCheck", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-check-e2e-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  function setupE2eFixture(
    stories: { name: string; scenarioPatterns: string[] }[],
    specContent: string | null,
  ) {
    const flow = "item-lifecycle";
    const storyDir = path.join(tmpDir, "my-app", "docs", "business-flow", flow, "story");
    fs.mkdirSync(storyDir, { recursive: true });

    for (const story of stories) {
      const patterns = story.scenarioPatterns.map((p) => `- ${p}`).join("\n");
      fs.writeFileSync(
        path.join(storyDir, `${story.name}.md`),
        `# Story\n\n## Scenario Patterns\n\n${patterns}\n`,
      );
    }

    if (specContent !== null) {
      const specDir = path.join(tmpDir, "my-app", "frontend", "e2e", "tests");
      fs.mkdirSync(specDir, { recursive: true });
      fs.writeFileSync(path.join(specDir, `${flow}.spec.ts`), specContent);
    }
  }

  it("reports missing-test-file when spec file does not exist", async () => {
    setupE2eFixture(
      [{ name: "admin--create-item", scenarioPatterns: ["Admin creates a new item"] }],
      null,
    );

    const errors = await runE2eSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-file",
        category: "e2e-scenario",
        expectedBasename: "item-lifecycle.spec.ts",
      }),
    );
  });

  it("reports missing describe block as missing-test-file", async () => {
    setupE2eFixture(
      [{ name: "admin--create-item", scenarioPatterns: ["Admin creates a new item"] }],
      'describe("other-story", () => { test("something", async () => {}); });',
    );

    const errors = await runE2eSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-file",
        category: "e2e-scenario",
        expectedBasename: 'describe("admin--create-item")',
      }),
    );
  });

  it("reports missing-test-case when scenario pattern not in spec", async () => {
    setupE2eFixture(
      [
        {
          name: "admin--create-item",
          scenarioPatterns: ["Admin creates a new item", "Admin creates item with all fields"],
        },
      ],
      'describe("admin--create-item", () => { test("Admin creates a new item", async () => {}); });',
    );

    const errors = await runE2eSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-test-case",
        category: "e2e-scenario",
        expectedBasename: "Admin creates item with all fields",
      }),
    );
  });

  it("reports extra-test-case when spec has test not in doc", async () => {
    setupE2eFixture(
      [{ name: "admin--create-item", scenarioPatterns: ["Admin creates a new item"] }],
      'describe("admin--create-item", () => { test("Admin creates a new item", async () => {}); test("Extra test", async () => {}); });',
    );

    const errors = await runE2eSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "extra-test-case",
        category: "e2e-scenario",
        expectedBasename: "Extra test",
      }),
    );
  });

  it("returns no errors when scenarios and spec match", async () => {
    setupE2eFixture(
      [
        {
          name: "admin--create-item",
          scenarioPatterns: ["Admin creates a new item"],
        },
        {
          name: "admin--activate-item",
          scenarioPatterns: ["Admin activates a DRAFT item"],
        },
      ],
      `
describe("admin--create-item", () => {
  test("Admin creates a new item", async () => {});
});
describe("admin--activate-item", () => {
  test("Admin activates a DRAFT item", async () => {});
});`,
    );

    const errors = await runE2eSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("skips stories with no Scenario Patterns", async () => {
    const flow = "item-lifecycle";
    const storyDir = path.join(tmpDir, "my-app", "docs", "business-flow", flow, "story");
    fs.mkdirSync(storyDir, { recursive: true });
    fs.writeFileSync(
      path.join(storyDir, "admin--create-item.md"),
      "# Create Item\n\n## Test Cases\n\n- some test\n",
    );

    const errors = await runE2eSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("reports orphaned-spec when spec has no matching business flow", async () => {
    setupE2eFixture(
      [{ name: "admin--create-item", scenarioPatterns: ["Admin creates a new item"] }],
      'describe("admin--create-item", () => { test("Admin creates a new item", async () => {}); });',
    );
    // Add an extra spec file with no matching flow
    const specDir = path.join(tmpDir, "my-app", "frontend", "e2e", "tests");
    fs.writeFileSync(path.join(specDir, "navigation.spec.ts"), 'test("nav", async () => {});');

    const errors = await runE2eSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "orphaned-spec",
        category: "e2e-scenario",
        expectedBasename: "navigation.spec.ts",
      }),
    );
  });
});

describe("parseActorNamesFromFixture", () => {
  it("extracts actor names from type union", () => {
    const content = `export type Actor = "admin" | "general-user";`;
    expect(parseActorNamesFromFixture(content)).toEqual(["admin", "general-user"]);
  });

  it("extracts single actor", () => {
    const content = `export type Actor = "admin";`;
    expect(parseActorNamesFromFixture(content)).toEqual(["admin"]);
  });

  it("returns empty array when no Actor type", () => {
    expect(parseActorNamesFromFixture("const x = 1;")).toEqual([]);
  });
});

describe("runActorSyncCheck", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-check-actor-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  function setupActorFixture(fixtureContent: string, actorDocs: string[]) {
    const fixtureDir = path.join(tmpDir, "my-app", "frontend", "e2e", "fixtures");
    const actorDocDir = path.join(tmpDir, "my-app", "docs", "actor");
    fs.mkdirSync(fixtureDir, { recursive: true });
    fs.mkdirSync(actorDocDir, { recursive: true });
    fs.writeFileSync(path.join(fixtureDir, "user.ts"), fixtureContent);
    for (const doc of actorDocs) {
      fs.writeFileSync(path.join(actorDocDir, `${doc}.md`), `# ${doc}\n`);
    }
  }

  it("returns no errors when actors match", async () => {
    setupActorFixture(`export type Actor = "admin" | "general-user";`, ["admin", "general-user"]);

    const errors = await runActorSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("reports missing-actor-doc when fixture has actor without doc", async () => {
    setupActorFixture(`export type Actor = "admin" | "general-user";`, ["admin"]);

    const errors = await runActorSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-actor-doc",
        category: "actor",
        expectedBasename: "general-user.md",
      }),
    );
  });

  it("reports missing-actor-fixture when doc has actor without fixture", async () => {
    setupActorFixture(`export type Actor = "admin";`, ["admin", "general-user"]);

    const errors = await runActorSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-actor-fixture",
        category: "actor",
        expectedBasename: "general-user",
      }),
    );
  });

  it("returns no errors when fixture file does not exist", async () => {
    const actorDocDir = path.join(tmpDir, "my-app", "docs", "actor");
    fs.mkdirSync(actorDocDir, { recursive: true });
    fs.writeFileSync(path.join(actorDocDir, "admin.md"), "# admin\n");

    const errors = await runActorSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });
});

describe("runScreenPageSyncCheck", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-check-screen-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  function setupScreenFixture(screenDocs: string[], pageObjects: { dir: string; name: string }[]) {
    const screenDir = path.join(tmpDir, "my-app", "docs", "screen");
    fs.mkdirSync(screenDir, { recursive: true });
    for (const name of screenDocs) {
      fs.writeFileSync(path.join(screenDir, `${name}.md`), `# ${name}\n`);
    }
    for (const { dir, name } of pageObjects) {
      const pageDir = path.join(tmpDir, "my-app", "frontend", "e2e", "pages", dir);
      fs.mkdirSync(pageDir, { recursive: true });
      fs.writeFileSync(path.join(pageDir, `${name}.ts`), `export class ${name} {}\n`);
    }
  }

  it("returns no errors when screen docs and page objects match", async () => {
    setupScreenFixture(
      ["login", "item-list"],
      [
        { dir: "auth", name: "login" },
        { dir: "item", name: "item-list" },
      ],
    );

    const errors = await runScreenPageSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("reports missing-page-object when screen doc has no page object", async () => {
    setupScreenFixture(["login", "item-list"], [{ dir: "auth", name: "login" }]);

    const errors = await runScreenPageSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-page-object",
        category: "screen",
        expectedBasename: "item-list.ts",
      }),
    );
  });

  it("allows page objects without screen docs", async () => {
    setupScreenFixture(
      ["login"],
      [
        { dir: "auth", name: "login" },
        { dir: "item", name: "item-list" },
      ],
    );

    const errors = await runScreenPageSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("returns no errors when neither screen docs nor page objects exist", async () => {
    fs.mkdirSync(path.join(tmpDir, "my-app"), { recursive: true });
    const errors = await runScreenPageSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });
});

describe("runSpecFixtureSyncCheck", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sync-check-spec-fixture-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  function setupSpecFixture(specs: string[], fixtures: string[]) {
    const specDir = path.join(tmpDir, "my-app", "frontend", "e2e", "tests");
    const fixtureDir = path.join(tmpDir, "my-app", "frontend", "e2e", "fixtures");
    fs.mkdirSync(specDir, { recursive: true });
    fs.mkdirSync(fixtureDir, { recursive: true });
    for (const name of specs) {
      fs.writeFileSync(path.join(specDir, `${name}.spec.ts`), 'test("foo", async () => {});');
    }
    for (const name of fixtures) {
      fs.writeFileSync(path.join(fixtureDir, `${name}.ts`), "export {};");
    }
  }

  it("returns no errors when each spec has a matching fixture", async () => {
    setupSpecFixture(
      ["item-lifecycle", "user-management"],
      ["user", "item-lifecycle", "user-management"],
    );

    const errors = await runSpecFixtureSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });

  it("reports missing-spec-fixture when spec has no matching fixture", async () => {
    setupSpecFixture(["item-lifecycle"], ["user"]);

    const errors = await runSpecFixtureSyncCheck("my-app", tmpDir);
    expect(errors).toContainEqual(
      expect.objectContaining({
        type: "missing-spec-fixture",
        category: "e2e-fixture",
        expectedBasename: "item-lifecycle.ts",
      }),
    );
  });

  it("returns no errors when no spec files exist", async () => {
    fs.mkdirSync(path.join(tmpDir, "my-app"), { recursive: true });
    const errors = await runSpecFixtureSyncCheck("my-app", tmpDir);
    expect(errors).toHaveLength(0);
  });
});
