Conversation
Co-authored-by: tm1000 <564256+tm1000@users.noreply.github.com>
Co-authored-by: tm1000 <564256+tm1000@users.noreply.github.com>
|
🧱 Stack PR · Base of stack Stack Structure:
|
|
@copilot ci fails with the following: |
There was a problem hiding this comment.
Pull request overview
This PR restores the repo’s CJS-based Jest test suite after upgrading @actions/core, @actions/artifact, and @actions/github to ESM-only versions by routing tests through CJS-compatible stubs and updating Jest/ts-jest configuration accordingly.
Changes:
- Added CJS stub implementations for
@actions/*modules and mapped them viajest.config.jsmoduleNameMapper. - Updated Jest/ts-jest TypeScript configuration and adjusted tests for Jest 30 typing/spy behavior changes.
- Addressed a TypeScript typing change in
fast-xml-parserv5 by adjusting theisArraycallback handling.
Reviewed changes
Copilot reviewed 8 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tsconfig.test.json |
Adds a dedicated TS config for tests to compile src/ and __tests__/ together. |
jest.config.js |
Configures ts-jest to use tsconfig.test.json and maps @actions/* imports to local CJS stubs. |
__mocks__/@actions/core.js |
Introduces a CJS stub for @actions/core, including summary and command behaviors used by tests. |
__mocks__/@actions/artifact.js |
Adds a minimal @actions/artifact CJS stub exporting DefaultArtifactClient. |
__mocks__/@actions/github.js |
Adds a minimal @actions/github CJS stub exporting getOctokit and context. |
__tests__/run.test.ts |
Mocks @actions/core in-test with jest.fn() APIs and switches assertions to jest.mocked(...) instead of spyOn. |
__tests__/functions.test.ts |
Adds an @actions/core mock wrapper with __esModule: true and updates setFailed mock typings. |
__tests__/artifacts.test.ts |
Adds explicit jest.fn<...>() generics to avoid never inference with mockResolvedValue (Jest 30). |
src/utils.ts |
Resolves a TS type error from fast-xml-parser v5 by asserting jpath as string when calling inArray. |
package-lock.json |
Updates lockfile metadata consistent with dependency updates (e.g., TypeScript marked as dev). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
__mocks__/@actions/core.js
Outdated
|
|
||
| function getMultilineInput(name, options) { | ||
| return getInput(name, options) | ||
| .split('\n') |
There was a problem hiding this comment.
getMultilineInput() splits only on \n, which will leave trailing \r characters when inputs contain Windows-style \r\n newlines. This diverges from @actions/core behavior and can cause subtle test differences. Consider splitting on /\r?\n/ instead.
| .split('\n') | |
| .split(/\r?\n/) |
__mocks__/@actions/core.js
Outdated
| function setOutput(name, value) { | ||
| const filePath = process.env['GITHUB_OUTPUT'] || ''; | ||
| if (filePath) { | ||
| const val = value !== null && value !== undefined ? String(value) : ''; | ||
| fs.appendFileSync(filePath, name + '=' + val + os.EOL); | ||
| return; |
There was a problem hiding this comment.
When GITHUB_OUTPUT is set, setOutput() appends name=value directly. The official file-command format uses a delimiter (name<<EOF ... EOF) to safely support multiline values and special characters; writing raw name=value can produce incorrect outputs if a value contains newlines. Consider implementing the delimiter-based format for GITHUB_OUTPUT (and similarly for GITHUB_ENV/GITHUB_STATE if these helpers are meant to be faithful).
| return inArray(jpath as string, [ | ||
| 'coverage.project.file', | ||
| 'coverage.project.package', | ||
| 'coverage.project.package.file', |
There was a problem hiding this comment.
Casting jpath to string sidesteps the updated fast-xml-parser typing (string | Matcher). If jpath is ever not a string at runtime, this will silently compare non-strings inside inArray(). Consider guarding with typeof jpath === 'string' ? inArray(jpath, ...) : false to keep type-safety without relying on an assertion.
Co-authored-by: tm1000 <564256+tm1000@users.noreply.github.com>
…mockModule Co-authored-by: tm1000 <564256+tm1000@users.noreply.github.com>
Co-authored-by: tm1000 <564256+tm1000@users.noreply.github.com>
... Fixed in commit Why
What changed now:
Security summary: CodeQL scan: 0 alerts. |
Code Coverage Report
Minimum allowed coverage is |
Summary
The
@actions/core,@actions/artifact, and@actions/githubpackages were upgraded to versions that are ESM-only (no CommonJS build). This broke the Jest test suite. In addition,eslint-plugin-github@6requireseslint@^8||^9, conflicting with the previously usedeslint@10.Root Cause
ESM-only packages cannot be
require()'d by Jest's CJS module system. An earlier attempt at usinguseESM: truein ts-jest failed for two reasons:resetModules: truereset the module registry before each individual test, making module-leveljest.mocked()references stale in ESM mode.__dirname/__filenameare not available in ES modules.Solution
Migrated the entire project to native ESM: ts-jest now compiles with
useESM: true, the test script usesNODE_OPTIONS=--experimental-vm-modules, andtsconfig.jsonoverrides tomodule: ESNext+moduleResolution: Bundlersoimport.meta.dirnameis valid whilenccstill bundles correctly. All__dirname/__filenameusages are replaced withimport.meta.dirname/import.meta.filename.eslintis downgraded to^9to satisfyeslint-plugin-github@6's peer requirement.Because
moduleNameMapperresolves stubs before the module graph is built, it is used for all packages that cannot be intercepted by late-hoistedjest.mockcalls in ESM VM-modules mode (@actions/core,@actions/artifact,@actions/github, andadm-zip).Changes
New / replaced files
__mocks__/@actions/core.ts— ESM TypeScript stub; commonly-used functions (getInput,setFailed,warning,error,info,debug,setOutput,summary, etc.) are exported asjest.fn()with real default implementations so snapshot tests capture the correct::command::stdout format and tests can verify calls viajest.mocked()without per-file factories.setFailedintentionally does not setprocess.exitCodeto avoid affecting Jest's exit handling.__mocks__/@actions/artifact.ts— ESM TypeScript stub;DefaultArtifactClientexported asjest.fn().__mocks__/@actions/github.ts— ESM TypeScript stub;getOctokitexported asjest.fn().__mocks__/adm-zip.ts— New ESM stub;adm-zipsits in a static import chain, so ajest.mockfactory cannot be hoisted early enough in ESM VM-modules mode.moduleNameMapperpre-resolves it before the module graph is built.tsconfig.test.json— Removed (no longer needed; a singletsconfig.jsoncovers everything).Modified files
jest.config.js— RemovedresetModules; addedextensionsToTreatAsEsm: ['.ts'],useESM: true, andadm-zipentry inmoduleNameMapper.package.json— Test script usesNODE_OPTIONS=--experimental-vm-modules jest;eslintdowngraded to^9.tsconfig.json— Overridesmodule: ESNextandmoduleResolution: Bundler.src/utils.ts—__dirnamereplaced withpath.dirname(fileURLToPath(import.meta.url));jpathcast retained.eslint.config.mjs— Added__mocks__/to eslint ignores..gitignore— Added patterns for temp test files.__tests__/functions.test.ts— Removed per-filejest.mock('@actions/core')factory; replaced alljest.spyOn(core, 'setFailed')calls withjest.mocked(core.setFailed).mockImplementation(...)(ESM module namespace properties are read-only sospyOncannot replace them).__tests__/run.test.ts— Removed per-filejest.mockfactories; replacedjest.mock('../src/utils', factory)withjest.unstable_mockModule(the ESM-native async mock API). Real util functions are imported via static imports at the top of the file and passed as closures into the factory (avoids circular load OOM).{ run }is imported dynamically inbeforeAllso it sees the mocked utils.__tests__/artifacts.test.ts— Removed broken per-testjest.mockfactories (now handled entirely by the stubs).Test Results
Security
CodeQL scan: 0 alerts
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.