Skip to content

Commit 970fe4a

Browse files
committed
Convert to ESM
1 parent d6b1edd commit 970fe4a

13 files changed

+2741
-425
lines changed

.node-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
21.6.2
1+
22.9.0

__fixtures__/core.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type * as core from '@actions/core'
2+
import { jest } from '@jest/globals'
3+
4+
export const debug = jest.fn<typeof core.debug>()
5+
export const error = jest.fn<typeof core.error>()
6+
export const info = jest.fn<typeof core.info>()
7+
export const getInput = jest.fn<typeof core.getInput>()
8+
export const setOutput = jest.fn<typeof core.setOutput>()
9+
export const setFailed = jest.fn<typeof core.setFailed>()
10+
export const warning = jest.fn<typeof core.warning>()

__fixtures__/wait.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { jest } from '@jest/globals'
2+
3+
export const wait = jest.fn<typeof import('../src/wait.js').wait>()

__tests__/index.test.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

__tests__/main.test.ts

Lines changed: 38 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,62 @@
11
/**
22
* Unit tests for the action's main functionality, src/main.ts
33
*
4-
* These should be run as if the action was called from a workflow.
5-
* Specifically, the inputs listed in `action.yml` should be set as environment
6-
* variables following the pattern `INPUT_<INPUT_NAME>`.
4+
* To mock dependencies in ESM, you can create fixtures that export mock
5+
* functions and objects. For example, the core module is mocked in this test,
6+
* so that the actual '@actions/core' module is not imported.
77
*/
8+
import { jest } from '@jest/globals'
9+
import * as core from '../__fixtures__/core.js'
10+
import { wait } from '../__fixtures__/wait.js'
811

9-
import * as core from '@actions/core'
10-
import * as main from '../src/main'
12+
// Mocks should be declared before the module being tested is imported.
13+
jest.unstable_mockModule('@actions/core', () => core)
14+
jest.unstable_mockModule('../src/wait.js', () => ({ wait }))
1115

12-
// Mock the action's main function
13-
const runMock = jest.spyOn(main, 'run')
16+
// The module being tested should be imported dynamically. This ensures that the
17+
// mocks are used in place of any actual dependencies.
18+
const { run } = await import('../src/main.js')
1419

15-
// Other utilities
16-
const timeRegex = /^\d{2}:\d{2}:\d{2}/
17-
18-
// Mock the GitHub Actions core library
19-
let debugMock: jest.SpiedFunction<typeof core.debug>
20-
let errorMock: jest.SpiedFunction<typeof core.error>
21-
let getInputMock: jest.SpiedFunction<typeof core.getInput>
22-
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>
23-
let setOutputMock: jest.SpiedFunction<typeof core.setOutput>
24-
25-
describe('action', () => {
20+
describe('main.ts', () => {
2621
beforeEach(() => {
27-
jest.clearAllMocks()
22+
// Set the action's inputs as return values from core.getInput().
23+
core.getInput.mockImplementation(() => '500')
2824

29-
debugMock = jest.spyOn(core, 'debug').mockImplementation()
30-
errorMock = jest.spyOn(core, 'error').mockImplementation()
31-
getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
32-
setFailedMock = jest.spyOn(core, 'setFailed').mockImplementation()
33-
setOutputMock = jest.spyOn(core, 'setOutput').mockImplementation()
25+
// Mock the wait function so that it does not actually wait.
26+
wait.mockImplementation(() => Promise.resolve('done!'))
3427
})
3528

36-
it('sets the time output', async () => {
37-
// Set the action's inputs as return values from core.getInput()
38-
getInputMock.mockImplementation(name => {
39-
switch (name) {
40-
case 'milliseconds':
41-
return '500'
42-
default:
43-
return ''
44-
}
45-
})
29+
afterEach(() => {
30+
jest.resetAllMocks()
31+
})
4632

47-
await main.run()
48-
expect(runMock).toHaveReturned()
33+
it('Sets the time output', async () => {
34+
await run()
4935

50-
// Verify that all of the core library functions were called correctly
51-
expect(debugMock).toHaveBeenNthCalledWith(1, 'Waiting 500 milliseconds ...')
52-
expect(debugMock).toHaveBeenNthCalledWith(
53-
2,
54-
expect.stringMatching(timeRegex)
55-
)
56-
expect(debugMock).toHaveBeenNthCalledWith(
57-
3,
58-
expect.stringMatching(timeRegex)
59-
)
60-
expect(setOutputMock).toHaveBeenNthCalledWith(
36+
// Verify the time output was set.
37+
expect(core.setOutput).toHaveBeenNthCalledWith(
6138
1,
6239
'time',
63-
expect.stringMatching(timeRegex)
40+
// Simple regex to match a time string in the format HH:MM:SS.
41+
expect.stringMatching(/^\d{2}:\d{2}:\d{2}/)
6442
)
65-
expect(errorMock).not.toHaveBeenCalled()
6643
})
6744

68-
it('sets a failed status', async () => {
69-
// Set the action's inputs as return values from core.getInput()
70-
getInputMock.mockImplementation(name => {
71-
switch (name) {
72-
case 'milliseconds':
73-
return 'this is not a number'
74-
default:
75-
return ''
76-
}
77-
})
45+
it('Sets a failed status', async () => {
46+
// Clear the getInput mock and return an invalid value.
47+
core.getInput.mockClear().mockReturnValueOnce('this is not a number')
48+
49+
// Clear the wait mock and return a rejected promise.
50+
wait
51+
.mockClear()
52+
.mockRejectedValueOnce(new Error('milliseconds is not a number'))
7853

79-
await main.run()
80-
expect(runMock).toHaveReturned()
54+
await run()
8155

82-
// Verify that all of the core library functions were called correctly
83-
expect(setFailedMock).toHaveBeenNthCalledWith(
56+
// Verify that the action was marked as failed.
57+
expect(core.setFailed).toHaveBeenNthCalledWith(
8458
1,
85-
'milliseconds not a number'
59+
'milliseconds is not a number'
8660
)
87-
expect(errorMock).not.toHaveBeenCalled()
8861
})
8962
})

__tests__/wait.test.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
/**
22
* Unit tests for src/wait.ts
33
*/
4-
5-
import { wait } from '../src/wait'
6-
import { expect } from '@jest/globals'
4+
import { wait } from '../src/wait.js'
75

86
describe('wait.ts', () => {
9-
it('throws an invalid number', async () => {
7+
it('Throws an invalid number', async () => {
108
const input = parseInt('foo', 10)
9+
1110
expect(isNaN(input)).toBe(true)
1211

13-
await expect(wait(input)).rejects.toThrow('milliseconds not a number')
12+
await expect(wait(input)).rejects.toThrow('milliseconds is not a number')
1413
})
1514

16-
it('waits with a valid number', async () => {
15+
it('Waits with a valid number', async () => {
1716
const start = new Date()
1817
await wait(500)
1918
const end = new Date()

jest.config.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// See: https://jestjs.io/docs/configuration
2+
3+
import type { JestConfigWithTsJest } from 'ts-jest'
4+
5+
const jestConfig: JestConfigWithTsJest = {
6+
clearMocks: true,
7+
collectCoverage: true,
8+
collectCoverageFrom: ['./src/**'],
9+
coverageDirectory: './coverage',
10+
coveragePathIgnorePatterns: ['/node_modules/', '/dist/'],
11+
coverageReporters: ['json-summary', 'text', 'lcov'],
12+
// Uncomment the below lines if you would like to enforce a coverage threshold
13+
// for your action. This will fail the build if the coverage is below the
14+
// specified thresholds.
15+
// coverageThreshold: {
16+
// global: {
17+
// branches: 100,
18+
// functions: 100,
19+
// lines: 100,
20+
// statements: 100
21+
// }
22+
// },
23+
extensionsToTreatAsEsm: ['.ts'],
24+
moduleFileExtensions: ['ts', 'js'],
25+
preset: 'ts-jest',
26+
reporters: ['default'],
27+
resolver: 'ts-jest-resolver',
28+
testEnvironment: 'node',
29+
testMatch: ['**/*.test.ts'],
30+
testPathIgnorePatterns: ['/dist/', '/node_modules/'],
31+
transform: {
32+
'^.+\\.ts$': [
33+
'ts-jest',
34+
{
35+
tsconfig: 'tsconfig.eslint.json',
36+
useESM: true
37+
}
38+
]
39+
},
40+
verbose: true
41+
}
42+
43+
export default jestConfig

0 commit comments

Comments
 (0)