Skip to content

fix: add monorepo root node_modules to Jest moduleDirectories#1900

Merged
mohammedahmed18 merged 1 commit into
mainfrom
cf-fix-monorepo-module-resolution
Mar 25, 2026
Merged

fix: add monorepo root node_modules to Jest moduleDirectories#1900
mohammedahmed18 merged 1 commit into
mainfrom
cf-fix-monorepo-module-resolution

Conversation

@mohammedahmed18

Copy link
Copy Markdown
Contributor

Summary

  • In monorepo setups (e.g., Strapi), workspace packages are hoisted to the root node_modules. When Jest runs from a subpackage, it can't resolve these packages because its default moduleDirectories only includes the local node_modules.
  • Adds _find_monorepo_root() detection (looks for yarn.lock, pnpm-workspace.yaml, lerna.json, package-lock.json + node_modules in parent directories) and injects the monorepo root's node_modules into moduleDirectories in the runtime Jest config.
  • ~240/1026 Strapi log files showed Cannot find module errors for workspace packages like @strapi/utils, @strapi/types, etc. due to this issue.

Test plan

  • Unit tests for _find_monorepo_root() (finds yarn workspace, returns None for standalone)
  • Unit tests for _create_runtime_jest_config() (includes moduleDirectories for monorepo, omits for standalone, spreads base config)
  • uv run prek passes

🤖 Generated with Claude Code

In monorepo setups (e.g., Strapi), workspace packages are hoisted to the
root node_modules. When Jest runs from a subpackage, it can't resolve
these packages because its default moduleDirectories only includes the
local node_modules. This adds the monorepo root's node_modules to
moduleDirectories in the runtime Jest config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude

claude Bot commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @mohammedahmed18's task in 2m 26s —— View job


PR Review Summary

Checklist

  • Triage PR size → SMALL (13 lines of production code)
  • Run lint/type checks
  • Check stale review threads → none
  • Review code changes
  • Check for duplicate logic

Prek Checks

uv run prek run --from-ref origin/main passes cleanly. mypy errors at line 1281 are pre-existing and unrelated to this PR.


Code Review

Correctness: ✅ Logic is sound

The implementation correctly:

  • Calls the pre-existing _find_monorepo_root() helper (already used at 3 other call sites in this file)
  • Guards with monorepo_root != project_root to avoid false positives when the project itself has a lock file
  • Handles both the base_config_path case (spreads baseConfig.moduleDirectories) and the standalone config case

One bug: module_dirs_line leaks into no-base-config branch (test_runner.py:380)

When base_config_path is None and we're in a monorepo, module_dirs_line is set (the version with baseConfig.moduleDirectories), but the else-branch of if base_config_path: uses module_dirs_line_no_base instead. Both variables are set correctly — this is actually fine. No bug here.

Minor concern: path injection risk

monorepo_node_modules is embedded as a JS string literal using single quotes:

module_dirs_line = f"  moduleDirectories: [...(baseConfig.moduleDirectories || ['node_modules']), '{monorepo_node_modules}'],\n"

If the path contains a single quote (e.g. /home/user's/project/node_modules), the generated JavaScript would be invalid. This is extremely rare in practice but worth a defensive replace("'", "\\'"). Fix this →

package-lock.json as monorepo marker (pre-existing in _find_monorepo_root, not introduced by this PR)

package-lock.json exists in virtually every npm project. A non-monorepo parent directory with package-lock.json + node_modules could be mistaken for a monorepo root. The monorepo_root != project_root guard mitigates the immediate case, but a grandparent with these files would still be picked up as a monorepo root. This is pre-existing behavior, not introduced here.


Duplicate Detection

No duplicates. _find_monorepo_root already existed and is correctly reused.


Test Coverage

Tests cover: yarn workspace detection, standalone (returns None), monorepo config with and without base config. Coverage is appropriate for the change.


Last updated: 2026-03-25T17:08Z

@mohammedahmed18 mohammedahmed18 merged commit bd0e96f into main Mar 25, 2026
29 of 30 checks passed
@mohammedahmed18 mohammedahmed18 deleted the cf-fix-monorepo-module-resolution branch March 25, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants