Skip to content

CLI locates its built-in reporters by resolving sibling packages at runtime #371

Description

@systemfsoftware-maker

Problem Statement

When you run stryker run, the CLI tells the engine where to find the built-in reporters (html, json, progress) by turning package names into file:// URLs, which the engine then imports at runtime. So the CLI only works when @systemfsoftware/stryker-js-html-reporter and @systemfsoftware/stryker-js-engine happen to be installed beside it under those exact names. Package the CLI so it carries its own code and those lookups fail. Built-in reporters are part of the product, not user extensions, so they should be imported in TypeScript and handed to the engine as values.

Goal

stryker run loads its built-in reporters through static imports: no reporter package is resolved by name at runtime, HostOptions carries no module-specifier channel for them, and plugins the user configures in stryker.config.json still load by name from the project.

Evidence: Current Behavior

packages/stryker-js/stryker-js-cli/src/Cli.ts:1119-1121 — the CLI builds the descriptors:

    reporterPluginModules: [
      import.meta.resolve('@systemfsoftware/stryker-js-html-reporter'),
      import.meta.resolve('@systemfsoftware/stryker-js-engine/builtin-reporters'),
    ],

packages/stryker-js/stryker-js-engine/src/Run.ts:399-400 — the engine merges them with user plugins and dynamically imports every descriptor:

    const descriptors: readonly string[] = [...pluginsList, ...appendPluginsList, ...env.reporterPluginModules]
    const loaded = yield* loadPlugins(descriptors, env.basePath).pipe(

Both at 7f11497e8b35da696e9f975df80f9714b91f79fa.

Orientation

  • The built-ins already exist as values: packages/stryker-js/stryker-js-engine/src/builtin-reporters.ts exports strykerPlugins, and packages/stryker-js/stryker-js-html-reporter/src/index.ts does the same. Nothing needs designing — the CLI just needs to import them instead of naming them.
  • The descriptor path stays as it is for user plugins: packages/stryker-js/stryker-js-engine/src/Config.ts:352-364 resolves plugins: [...] from stryker.config.json against the project directory.
  • Gold paths that must keep passing: pnpm --filter @systemfsoftware/stryker-js-cli test:contract and pnpm --filter @systemfsoftware/stryker-js-engine test. The contract lane packs the CLI and installs the tarball alone (global-setup.ts), which is the environment where a runtime lookup has nothing to find.
  • No test currently asserts the html report artifact is written; add that assertion so the html reporter's registration is observable and cannot silently vanish.

Non-Counting Outcomes

  • Replacing import.meta.resolve with hard-coded relative paths into sibling dist/ output — same cross-package knowledge, just harder to see.
  • Removing the field but leaving the reporters unregistered, so runs succeed while the html report silently stops being produced.
  • Deleting or stubbing consumer-plugin loading to make the types work.
  • Verifying with exit codes only — a run that writes no report still exits 0.

Acceptance Criteria

  • HostOptions has no reporterPluginModules member, so reintroducing the CLI-side descriptor fails pnpm --filter @systemfsoftware/stryker-js-cli typecheck.
  • grep -rn "import.meta.resolve" packages/stryker-js/stryker-js-cli/src returns no reporter package specifier.
  • pnpm --filter @systemfsoftware/stryker-js-cli test:contract exits 0 and includes a new assertion that an html-reporter run writes the report artifact to the configured output path.
  • A fixture project that configures a plugin by name in stryker.config.json completes a run with a terminal stream event.
  • pnpm --filter @systemfsoftware/stryker-js-engine test exits 0.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions