Skip to content

Commit 18d2829

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 18d2829

9 files changed

Lines changed: 36681 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: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,68 @@
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+
jest.unstable_mockModule('@actions/core', () => ({
40+
debug: debugMock,
41+
info: infoMock,
42+
warning: jest.fn(),
43+
error: errorMock,
44+
getInput: getInputMock,
45+
setFailed: setFailedMock,
46+
setOutput: setOutputMock,
47+
summary: {
48+
addRaw: jest.fn().mockReturnThis(),
49+
write: jest.fn<() => Promise<void>>().mockResolvedValue(undefined)
50+
}
51+
}))
3552

3653
// Mock @actions/artifact and @actions/github
37-
jest.mock('@actions/artifact')
38-
jest.mock('@actions/github')
54+
const uploadArtifactMock = jest
55+
.fn<() => Promise<{ size: number; id: number }>>()
56+
.mockResolvedValue({ size: 0, id: 0 })
57+
58+
jest.unstable_mockModule('@actions/artifact', () => ({
59+
DefaultArtifactClient: jest.fn().mockImplementation(() => ({
60+
uploadArtifact: uploadArtifactMock
61+
}))
62+
}))
63+
64+
jest.unstable_mockModule('@actions/github', () => ({
65+
context: {
66+
repo: { owner: 'test', repo: 'test' },
67+
runId: 123
68+
}
69+
}))
70+
71+
// Dynamic imports after mocking
72+
const main = await import('../src/main')
73+
const { getMSYS } = await import('../src/get-msys')
3974

4075
// Set GitHub summary file
4176
const gitHubStepSummaryFile = path.resolve(
@@ -57,18 +92,9 @@ describe('action', () => {
5792

5893
jest.clearAllMocks()
5994

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()
95+
debugMock.mockImplementation(msg => console.log(`::debug::${msg}`))
96+
infoMock.mockImplementation(msg => console.log(`::info::${msg}`))
97+
errorMock.mockImplementation(msg => console.log(`::error::${msg}`))
7298
})
7399

74100
it(
@@ -101,7 +127,6 @@ describe('action', () => {
101127
})
102128

103129
await main.run()
104-
expect(runMock).toHaveReturned()
105130

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

0 commit comments

Comments
 (0)