Skip to content

Commit cad9952

Browse files
JKRTclaude
andcommitted
Update @actions/core to v3
This updates @actions/core from v2 to v3, which is an ESM-only package. Changes required for ESM compatibility: - Add jest.config.mjs with ts-jest ESM preset - Update test script to use --experimental-vm-modules - Update test files to use jest.unstable_mockModule() for ESM mocking - Import jest from @jest/globals instead of using globals - Use dynamic imports after setting up mocks - Fix __dirname usage in src/collect.ts using import.meta.url Fixes #66 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fa6245e commit cad9952

9 files changed

Lines changed: 36696 additions & 6349 deletions

File tree

__tests__/collect.test.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,39 @@
44

55
import * as fs from 'fs'
66
import * as path from 'path'
7-
import * as artifact from '@actions/artifact'
8-
import { expect } from '@jest/globals'
9-
import { copyHtmlFilesSync, uploadArtifacts } from '../src/collect'
7+
import {
8+
expect,
9+
jest,
10+
describe,
11+
beforeEach,
12+
afterEach,
13+
it
14+
} from '@jest/globals'
1015

1116
const tempTestDir = path.join('__tests__', 'tmp-collect')
1217

1318
// Mock @actions/artifact
14-
jest.mock('@actions/artifact')
15-
jest.mock('@actions/github')
19+
const uploadArtifactMock = jest
20+
.fn<() => Promise<{ size: number; id: number }>>()
21+
.mockResolvedValue({ size: 0, id: 0 })
22+
23+
const DefaultArtifactClientMock = jest.fn().mockImplementation(() => ({
24+
uploadArtifact: uploadArtifactMock
25+
}))
26+
27+
jest.unstable_mockModule('@actions/artifact', () => ({
28+
DefaultArtifactClient: DefaultArtifactClientMock
29+
}))
30+
31+
jest.unstable_mockModule('@actions/github', () => ({
32+
context: {
33+
repo: { owner: 'test', repo: 'test' },
34+
runId: 123
35+
}
36+
}))
37+
38+
// Dynamic imports after mocking
39+
const { copyHtmlFilesSync, uploadArtifacts } = await import('../src/collect')
1640

1741
function mockFileStructure(
1842
libraryName: string,
@@ -107,13 +131,6 @@ describe('collect.ts', () => {
107131
const targetDir = path.join(tempTestDir, 'html')
108132
mockFileStructure(libraryName, libraryVersion, modelPrefix, omLibTestingDir)
109133

110-
const DefaultArtifactClientMock = jest
111-
.spyOn(artifact, 'DefaultArtifactClient')
112-
.mockImplementation()
113-
const uploadArtifactMock = jest
114-
.spyOn(artifact.DefaultArtifactClient.prototype, 'uploadArtifact')
115-
.mockImplementation()
116-
117134
copyHtmlFilesSync(
118135
libraryName,
119136
libraryVersion,

__tests__/index.test.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@
22
* Unit tests for the action's entrypoint, src/index.ts
33
*/
44

5-
import * as main from '../src/main'
5+
import { expect, jest, describe, it } from '@jest/globals'
66

7-
// Mock the action's entrypoint
8-
const runMock = jest.spyOn(main, 'run').mockImplementation()
7+
// Mock the main module before importing
8+
const runMock = jest.fn<() => Promise<void>>().mockResolvedValue(undefined)
9+
10+
jest.unstable_mockModule('../src/main', () => ({
11+
run: runMock
12+
}))
913

1014
describe('index', () => {
1115
it('calls run when imported', async () => {
12-
// eslint-disable-next-line @typescript-eslint/no-require-imports
13-
require('../src/index')
16+
// Dynamic import after mocking
17+
await import('../src/index')
1418

1519
expect(runMock).toHaveBeenCalled()
1620
})

__tests__/inputs.test.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,32 @@
33
*/
44

55
import * as path from 'path'
6-
import * as core from '@actions/core'
7-
import { expect } from '@jest/globals'
8-
import { ActionInputs, ActionInputsInterface } from '../src/inputs'
6+
import { expect, jest, describe, beforeEach, it } from '@jest/globals'
97

108
const modelicaFile = path.resolve('examples/MyLibrary/package.mo')
119
const referenceFilesDir = path.resolve('examples/ReferenceFiles')
1210

13-
// Mock the GitHub Actions core library
14-
let getInputMock: jest.SpyInstance
11+
// Mock @actions/core before importing modules that use it
12+
const getInputMock =
13+
jest.fn<(name: string, options?: { required?: boolean }) => string>()
14+
15+
jest.unstable_mockModule('@actions/core', () => ({
16+
getInput: getInputMock,
17+
debug: jest.fn(),
18+
info: jest.fn(),
19+
warning: jest.fn(),
20+
error: jest.fn(),
21+
setFailed: jest.fn(),
22+
setOutput: jest.fn()
23+
}))
24+
25+
// Dynamic import after mocking
26+
const { ActionInputs } = await import('../src/inputs')
27+
import type { ActionInputsInterface } from '../src/inputs'
1528

1629
describe('inputs.ts', () => {
1730
beforeEach(() => {
1831
jest.clearAllMocks()
19-
getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
2032
})
2133

2234
it('Read inputs', async () => {

__tests__/main.test.ts

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,81 @@
99
import * as fs from 'fs'
1010
import * as os from 'os'
1111
import * as path from 'path'
12-
import * as core from '@actions/core'
13-
import * as main from '../src/main'
14-
import { getMSYS } from '../src/get-msys'
12+
import { expect, jest, describe, beforeEach, afterAll, it } from '@jest/globals'
1513

1614
// Some expected string
1715
const mdCoverageTable = `| Total | Frontend | Backend | SimCode | Templates | Compilation | Simulation | Verification |
1816
| --- | --- | --- | --- | --- | --- | --- | --- |
1917
| 2 | 2 | 2 | 2 | 2 | 2 | 2 | 1 |`
2018

21-
// Mock the action's main function
22-
const runMock = jest.spyOn(main, 'run')
2319
const modelicaFile = path.resolve(
2420
path.join('examples', 'MyLibrary', 'package.mo')
2521
)
2622
const referenceFilesDir = path.resolve(path.join('examples', 'ReferenceFiles'))
2723

2824
// Mock the GitHub Actions core library
29-
let debugMock: jest.SpyInstance
30-
let errorMock: jest.SpyInstance
31-
let infoMock: jest.SpyInstance
32-
let getInputMock: jest.SpyInstance
33-
let setFailedMock: jest.SpyInstance
34-
let setOutputMock: jest.SpyInstance
25+
const debugMock = jest
26+
.fn<(message: string) => void>()
27+
.mockImplementation(msg => console.log(`::debug::${msg}`))
28+
const infoMock = jest
29+
.fn<(message: string) => void>()
30+
.mockImplementation(msg => console.log(`::info::${msg}`))
31+
const errorMock = jest
32+
.fn<(message: string | Error) => void>()
33+
.mockImplementation(msg => console.log(`::error::${msg}`))
34+
const getInputMock =
35+
jest.fn<(name: string, options?: { required?: boolean }) => string>()
36+
const setFailedMock = jest.fn<(message: string | Error) => void>()
37+
const setOutputMock = jest.fn<(name: string, value: unknown) => void>()
38+
39+
// Create a summary mock that actually writes to the file
40+
let summaryBuffer = ''
41+
const summaryMock = {
42+
addRaw: jest.fn((text: string) => {
43+
summaryBuffer += text
44+
return summaryMock
45+
}),
46+
write: jest.fn(async () => {
47+
const summaryFile = process.env.GITHUB_STEP_SUMMARY
48+
if (summaryFile) {
49+
fs.appendFileSync(summaryFile, summaryBuffer)
50+
}
51+
summaryBuffer = ''
52+
})
53+
}
54+
55+
jest.unstable_mockModule('@actions/core', () => ({
56+
debug: debugMock,
57+
info: infoMock,
58+
warning: jest.fn(),
59+
error: errorMock,
60+
getInput: getInputMock,
61+
setFailed: setFailedMock,
62+
setOutput: setOutputMock,
63+
summary: summaryMock
64+
}))
3565

3666
// Mock @actions/artifact and @actions/github
37-
jest.mock('@actions/artifact')
38-
jest.mock('@actions/github')
67+
const uploadArtifactMock = jest
68+
.fn<() => Promise<{ size: number; id: number }>>()
69+
.mockResolvedValue({ size: 0, id: 0 })
70+
71+
jest.unstable_mockModule('@actions/artifact', () => ({
72+
DefaultArtifactClient: jest.fn().mockImplementation(() => ({
73+
uploadArtifact: uploadArtifactMock
74+
}))
75+
}))
76+
77+
jest.unstable_mockModule('@actions/github', () => ({
78+
context: {
79+
repo: { owner: 'test', repo: 'test' },
80+
runId: 123
81+
}
82+
}))
83+
84+
// Dynamic imports after mocking
85+
const main = await import('../src/main')
86+
const { getMSYS } = await import('../src/get-msys')
3987

4088
// Set GitHub summary file
4189
const gitHubStepSummaryFile = path.resolve(
@@ -56,19 +104,12 @@ describe('action', () => {
56104
fs.writeFileSync(gitHubStepSummaryFile, '', { flag: 'w' })
57105

58106
jest.clearAllMocks()
107+
// Reset summary buffer
108+
summaryBuffer = ''
59109

60-
debugMock = jest
61-
.spyOn(core, 'debug')
62-
.mockImplementation(msg => console.log(`::debug::${msg}`))
63-
infoMock = jest
64-
.spyOn(core, 'info')
65-
.mockImplementation(msg => console.log(`::info::${msg}`))
66-
errorMock = jest
67-
.spyOn(core, 'error')
68-
.mockImplementation(msg => console.log(`::error::${msg}`))
69-
getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
70-
setFailedMock = jest.spyOn(core, 'setFailed').mockImplementation()
71-
setOutputMock = jest.spyOn(core, 'setOutput').mockImplementation()
110+
debugMock.mockImplementation(msg => console.log(`::debug::${msg}`))
111+
infoMock.mockImplementation(msg => console.log(`::info::${msg}`))
112+
errorMock.mockImplementation(msg => console.log(`::error::${msg}`))
72113
})
73114

74115
it(
@@ -101,7 +142,6 @@ describe('action', () => {
101142
})
102143

103144
await main.run()
104-
expect(runMock).toHaveReturned()
105145

106146
// Verify that all of the core library functions were called correctly
107147
expect(debugMock).toHaveBeenNthCalledWith(1, 'Get inputs')

0 commit comments

Comments
 (0)