@ronaldphilipsen/local-action 0.0.0-stage → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.checkov.yml +3 -0
- package/.env.example +379 -0
- package/.github/codeql/codeql-config.yml +7 -0
- package/.github/copilot-instructions.md +79 -0
- package/.github/dependabot.yml +32 -0
- package/.github/workflows/codeql-analysis.yml +53 -0
- package/.github/workflows/continuous-delivery.yml +93 -0
- package/.github/workflows/continuous-integration.yml +382 -0
- package/.github/workflows/linter.yml +47 -0
- package/.github/workflows/release.yaml +100 -0
- package/.github/workflows/version-check.yml +44 -0
- package/.grype.yml +151 -0
- package/.markdown-lint.yml +7 -0
- package/.mega-linter.yml +188 -0
- package/.node-version +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc.yml +14 -0
- package/.vscode/launch.json +15 -0
- package/.vscode/mcp.json +9 -0
- package/.vscode/settings.json +15 -0
- package/.vscode/tasks.json +51 -0
- package/.yaml-lint.yml +10 -0
- package/CHANGELOG.md +75 -0
- package/CODEOWNERS +3 -0
- package/CODE_OF_CONDUCT.md +74 -0
- package/CONTRIBUTING.md +140 -0
- package/LICENSE +21 -0
- package/README.md +277 -2
- package/SECURITY.md +42 -0
- package/SUPPORT.md +19 -0
- package/__fixtures__/@actions/core.ts +14 -0
- package/__fixtures__/@actions/exec.ts +9 -0
- package/__fixtures__/@actions/github.ts +3 -0
- package/__fixtures__/@actions/http-client.ts +9 -0
- package/__fixtures__/@actions/io.ts +9 -0
- package/__fixtures__/@octokit/rest.ts +18 -0
- package/__fixtures__/crypto.ts +7 -0
- package/__fixtures__/fs.ts +27 -0
- package/__fixtures__/javascript/no-export/.env.fixture +2 -0
- package/__fixtures__/javascript/no-export/action.yml +16 -0
- package/__fixtures__/javascript/no-export/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/no-export/package.json +12 -0
- package/__fixtures__/javascript/no-export/src/index.js +0 -0
- package/__fixtures__/javascript/no-export/src/main.js +0 -0
- package/__fixtures__/javascript/no-import/.env.fixture +2 -0
- package/__fixtures__/javascript/no-import/action.yml +16 -0
- package/__fixtures__/javascript/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/no-import/package.json +12 -0
- package/__fixtures__/javascript/no-import/src/index.js +3 -0
- package/__fixtures__/javascript/no-import/src/main.js +7 -0
- package/__fixtures__/javascript/success/.env.fixture +2 -0
- package/__fixtures__/javascript/success/action.yml +16 -0
- package/__fixtures__/javascript/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/success/package.json +12 -0
- package/__fixtures__/javascript/success/post/index.js +3 -0
- package/__fixtures__/javascript/success/post/main.js +13 -0
- package/__fixtures__/javascript/success/pre/index.js +3 -0
- package/__fixtures__/javascript/success/pre/main.js +13 -0
- package/__fixtures__/javascript/success/src/index.js +3 -0
- package/__fixtures__/javascript/success/src/main.js +13 -0
- package/__fixtures__/javascript-esm/no-import/.env.fixture +2 -0
- package/__fixtures__/javascript-esm/no-import/action.yml +16 -0
- package/__fixtures__/javascript-esm/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript-esm/no-import/package.json +13 -0
- package/__fixtures__/javascript-esm/no-import/src/index.js +3 -0
- package/__fixtures__/javascript-esm/no-import/src/main.js +7 -0
- package/__fixtures__/javascript-esm/success/.env.fixture +2 -0
- package/__fixtures__/javascript-esm/success/action.yml +16 -0
- package/__fixtures__/javascript-esm/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript-esm/success/package.json +13 -0
- package/__fixtures__/javascript-esm/success/post/index.js +3 -0
- package/__fixtures__/javascript-esm/success/post/main.js +13 -0
- package/__fixtures__/javascript-esm/success/pre/index.js +3 -0
- package/__fixtures__/javascript-esm/success/pre/main.js +13 -0
- package/__fixtures__/javascript-esm/success/src/index.js +3 -0
- package/__fixtures__/javascript-esm/success/src/main.js +13 -0
- package/__fixtures__/path.ts +7 -0
- package/__fixtures__/payloads/issue_opened.json +33 -0
- package/__fixtures__/stream/promises.ts +3 -0
- package/__fixtures__/tsconfig-paths.ts +4 -0
- package/__fixtures__/typescript/no-import/.env.fixture +2 -0
- package/__fixtures__/typescript/no-import/action.yml +16 -0
- package/__fixtures__/typescript/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/no-import/package.json +15 -0
- package/__fixtures__/typescript/no-import/src/index.ts +3 -0
- package/__fixtures__/typescript/no-import/src/main.ts +3 -0
- package/__fixtures__/typescript/no-import/tsconfig.json +20 -0
- package/__fixtures__/typescript/success/.env.fixture +2 -0
- package/__fixtures__/typescript/success/action.yml +16 -0
- package/__fixtures__/typescript/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/success/package.json +15 -0
- package/__fixtures__/typescript/success/post/index.ts +3 -0
- package/__fixtures__/typescript/success/post/main.ts +9 -0
- package/__fixtures__/typescript/success/pre/index.ts +3 -0
- package/__fixtures__/typescript/success/pre/main.ts +9 -0
- package/__fixtures__/typescript/success/src/index.ts +3 -0
- package/__fixtures__/typescript/success/src/main.ts +9 -0
- package/__fixtures__/typescript/success/tsconfig.json +20 -0
- package/__fixtures__/typescript/success-yaml/.env.fixture +2 -0
- package/__fixtures__/typescript/success-yaml/action.yaml +16 -0
- package/__fixtures__/typescript/success-yaml/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/success-yaml/package.json +15 -0
- package/__fixtures__/typescript/success-yaml/post/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/post/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/pre/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/pre/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/src/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/src/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/tsconfig.json +20 -0
- package/__fixtures__/typescript-esm/no-export/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/no-export/action.yml +17 -0
- package/__fixtures__/typescript-esm/no-export/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/no-export/package.json +17 -0
- package/__fixtures__/typescript-esm/no-export/src/index.ts +0 -0
- package/__fixtures__/typescript-esm/no-export/src/main.ts +0 -0
- package/__fixtures__/typescript-esm/no-export/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/no-import/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/no-import/action.yml +17 -0
- package/__fixtures__/typescript-esm/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/no-import/package.json +17 -0
- package/__fixtures__/typescript-esm/no-import/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/no-import/src/main.ts +3 -0
- package/__fixtures__/typescript-esm/no-import/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/success/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/success/action.yml +17 -0
- package/__fixtures__/typescript-esm/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/success/package.json +17 -0
- package/__fixtures__/typescript-esm/success/post/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/post/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/pre/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/pre/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/src/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/action.yml +17 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/package.json +17 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/src/main.ts +9 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/tsconfig.json +21 -0
- package/__tests__/command.test.ts +224 -0
- package/__tests__/stubs/artifact/internal/client.test.ts +340 -0
- package/__tests__/stubs/artifact/internal/delete/delete-artifact.test.ts +152 -0
- package/__tests__/stubs/artifact/internal/download/download-artifact.test.ts +119 -0
- package/__tests__/stubs/artifact/internal/find/get-artifact.test.ts +237 -0
- package/__tests__/stubs/artifact/internal/find/list-artifacts.test.ts +218 -0
- package/__tests__/stubs/artifact/internal/find/retry-options.test.ts +54 -0
- package/__tests__/stubs/artifact/internal/shared/config.test.ts +91 -0
- package/__tests__/stubs/artifact/internal/shared/errors.test.ts +38 -0
- package/__tests__/stubs/artifact/internal/shared/user-agent.test.ts +22 -0
- package/__tests__/stubs/artifact/internal/upload/path-and-artifact-name-validation.test.ts +53 -0
- package/__tests__/stubs/artifact/internal/upload/upload-artifact.test.ts +126 -0
- package/__tests__/stubs/artifact/internal/upload/upload-zip-specification.test.ts +49 -0
- package/__tests__/stubs/cache/cache.test.ts +357 -0
- package/__tests__/stubs/cache/errors.test.ts +55 -0
- package/__tests__/stubs/cache/internal/cacheUtils.test.ts +109 -0
- package/__tests__/stubs/cache/internal/constants.test.ts +81 -0
- package/__tests__/stubs/cache/internal/tar.test.ts +129 -0
- package/__tests__/stubs/core/core.test.ts +760 -0
- package/__tests__/stubs/core/path-utils.test.ts +45 -0
- package/__tests__/stubs/core/platform.test.ts +89 -0
- package/__tests__/stubs/core/summary.test.ts +455 -0
- package/__tests__/stubs/env.test.ts +72 -0
- package/__tests__/stubs/github/context.test.ts +73 -0
- package/__tests__/stubs/github/github.test.ts +15 -0
- package/__tests__/stubs/github/internal/utils.test.ts +98 -0
- package/__tests__/stubs/github/utils.test.ts +16 -0
- package/__tests__/utils/config.test.ts +78 -0
- package/__tests__/utils/output.test.ts +32 -0
- package/__tests__/utils/package.test.ts +33 -0
- package/badges/coverage.svg +1 -0
- package/bin/local-action.js +121 -0
- package/docs/create-a-job-summary.md +32 -0
- package/docs/debugging-in-vscode.md +27 -0
- package/docs/img/job-summary.png +0 -0
- package/docs/supported-functionality.md +126 -0
- package/eslint.config.mjs +74 -0
- package/jest.config.ts +41 -0
- package/package.json +93 -4
- package/src/command.ts +171 -0
- package/src/commands/run.ts +616 -0
- package/src/index.ts +21 -0
- package/src/stubs/artifact/artifact.ts +17 -0
- package/src/stubs/artifact/internal/client.ts +400 -0
- package/src/stubs/artifact/internal/delete/delete-artifact.ts +126 -0
- package/src/stubs/artifact/internal/download/download-artifact.ts +309 -0
- package/src/stubs/artifact/internal/find/get-artifact.ts +135 -0
- package/src/stubs/artifact/internal/find/list-artifacts.ts +188 -0
- package/src/stubs/artifact/internal/find/retry-options.ts +57 -0
- package/src/stubs/artifact/internal/shared/config.ts +64 -0
- package/src/stubs/artifact/internal/shared/errors.ts +53 -0
- package/src/stubs/artifact/internal/shared/interfaces.ts +195 -0
- package/src/stubs/artifact/internal/shared/user-agent.ts +13 -0
- package/src/stubs/artifact/internal/upload/path-and-artifact-name-validation.ts +92 -0
- package/src/stubs/artifact/internal/upload/upload-artifact.ts +127 -0
- package/src/stubs/artifact/internal/upload/upload-zip-specification.ts +108 -0
- package/src/stubs/artifact/internal/upload/zip.ts +122 -0
- package/src/stubs/cache/cache.ts +334 -0
- package/src/stubs/cache/errors.ts +31 -0
- package/src/stubs/cache/interfaces.ts +4 -0
- package/src/stubs/cache/internal/cacheUtils.ts +207 -0
- package/src/stubs/cache/internal/constants.ts +45 -0
- package/src/stubs/cache/internal/tar.ts +374 -0
- package/src/stubs/cache/options.ts +91 -0
- package/src/stubs/core/core.ts +743 -0
- package/src/stubs/core/path-utils.ts +39 -0
- package/src/stubs/core/platform.ts +132 -0
- package/src/stubs/core/summary.ts +399 -0
- package/src/stubs/env.ts +40 -0
- package/src/stubs/github/context.ts +94 -0
- package/src/stubs/github/github.ts +29 -0
- package/src/stubs/github/interfaces.ts +52 -0
- package/src/stubs/github/internal/utils.ts +83 -0
- package/src/stubs/github/utils.ts +52 -0
- package/src/types/quibble.d.ts +5 -0
- package/src/types.ts +116 -0
- package/src/utils/config.ts +47 -0
- package/src/utils/output.ts +20 -0
- package/src/utils/package.ts +38 -0
- package/tsconfig.base.json +29 -0
- package/tsconfig.eslint.json +22 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import * as core from '../../../../../__fixtures__/@actions/core.js'
|
|
3
|
+
|
|
4
|
+
jest.unstable_mockModule('../../../../../src/stubs/core/core.js', () => core)
|
|
5
|
+
|
|
6
|
+
const pathAndArtifactNameValidation =
|
|
7
|
+
await import('../../../../../src/stubs/artifact/internal/upload/path-and-artifact-name-validation.js')
|
|
8
|
+
|
|
9
|
+
describe('path-and-artifact-name-validation', () => {
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
jest.resetAllMocks()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('validateArtifactName', () => {
|
|
15
|
+
it('Throws if no name is provided', () => {
|
|
16
|
+
expect(() =>
|
|
17
|
+
pathAndArtifactNameValidation.validateArtifactName('')
|
|
18
|
+
).toThrow('Provided artifact name input during validation is empty')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('Throws if name contains invalid characters', () => {
|
|
22
|
+
expect(() =>
|
|
23
|
+
pathAndArtifactNameValidation.validateArtifactName('invalid<name')
|
|
24
|
+
).toThrow()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('Does not throw if name is valid', () => {
|
|
28
|
+
expect(() =>
|
|
29
|
+
pathAndArtifactNameValidation.validateArtifactName('valid-name')
|
|
30
|
+
).not.toThrow()
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
describe('validateFilePath', () => {
|
|
35
|
+
it('Throws if no path is provided', () => {
|
|
36
|
+
expect(() => pathAndArtifactNameValidation.validateFilePath('')).toThrow(
|
|
37
|
+
'Provided file path input during validation is empty'
|
|
38
|
+
)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('Throws if path contains invalid characters', () => {
|
|
42
|
+
expect(() =>
|
|
43
|
+
pathAndArtifactNameValidation.validateFilePath('invalid<path')
|
|
44
|
+
).toThrow()
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('Does not throw if path is valid', () => {
|
|
48
|
+
expect(() =>
|
|
49
|
+
pathAndArtifactNameValidation.validateFilePath('valid/path')
|
|
50
|
+
).not.toThrow()
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import { type Stats } from 'fs'
|
|
3
|
+
import * as core from '../../../../../__fixtures__/@actions/core.js'
|
|
4
|
+
import * as crypto from '../../../../../__fixtures__/crypto.js'
|
|
5
|
+
import * as fs from '../../../../../__fixtures__/fs.js'
|
|
6
|
+
import * as stream from '../../../../../__fixtures__/stream/promises.js'
|
|
7
|
+
import { ResetCoreMetadata } from '../../../../../src/stubs/core/core.js'
|
|
8
|
+
import { EnvMeta, ResetEnvMetadata } from '../../../../../src/stubs/env.js'
|
|
9
|
+
|
|
10
|
+
const validateArtifactName = jest.fn()
|
|
11
|
+
const validateRootDirectory = jest.fn()
|
|
12
|
+
const getUploadZipSpecification = jest.fn()
|
|
13
|
+
const createZipUploadStream = jest.fn()
|
|
14
|
+
const zipUploadStream = {
|
|
15
|
+
on: () => zipUploadStream,
|
|
16
|
+
pipe: () => zipUploadStream,
|
|
17
|
+
setEncoding: () => zipUploadStream
|
|
18
|
+
}
|
|
19
|
+
const hashStream = {
|
|
20
|
+
end: () => hashStream,
|
|
21
|
+
read: () => hashStream
|
|
22
|
+
}
|
|
23
|
+
const writeStream = {
|
|
24
|
+
on: () => writeStream
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
jest.unstable_mockModule('crypto', () => crypto)
|
|
28
|
+
jest.unstable_mockModule('fs', () => fs)
|
|
29
|
+
jest.unstable_mockModule('stream/promises', () => stream)
|
|
30
|
+
jest.unstable_mockModule('../../../../../src/stubs/core/core.js', () => core)
|
|
31
|
+
jest.unstable_mockModule(
|
|
32
|
+
'../../../../../src/stubs/artifact/internal/upload/upload-zip-specification.js',
|
|
33
|
+
() => ({
|
|
34
|
+
validateRootDirectory,
|
|
35
|
+
getUploadZipSpecification
|
|
36
|
+
})
|
|
37
|
+
)
|
|
38
|
+
jest.unstable_mockModule(
|
|
39
|
+
'../../../../../src/stubs/artifact/internal/upload/path-and-artifact-name-validation.js',
|
|
40
|
+
() => ({
|
|
41
|
+
validateArtifactName
|
|
42
|
+
})
|
|
43
|
+
)
|
|
44
|
+
jest.unstable_mockModule(
|
|
45
|
+
'../../../../../src/stubs/artifact/internal/upload/zip.js',
|
|
46
|
+
() => ({
|
|
47
|
+
createZipUploadStream
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const uploadArtifact =
|
|
52
|
+
await import('../../../../../src/stubs/artifact/internal/upload/upload-artifact.js')
|
|
53
|
+
|
|
54
|
+
describe('upload-artifacts', () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
// Reset environment variables
|
|
57
|
+
process.env.LOCAL_ACTION_ARTIFACT_PATH = '/tmp/artifacts'
|
|
58
|
+
|
|
59
|
+
// Reset metadata
|
|
60
|
+
ResetEnvMetadata()
|
|
61
|
+
ResetCoreMetadata()
|
|
62
|
+
|
|
63
|
+
// Reset mocks
|
|
64
|
+
getUploadZipSpecification.mockImplementation(() => [
|
|
65
|
+
{
|
|
66
|
+
sourcePath: 'source-path',
|
|
67
|
+
destinationPath: 'destination-path',
|
|
68
|
+
stats: {} as Stats
|
|
69
|
+
}
|
|
70
|
+
])
|
|
71
|
+
createZipUploadStream.mockImplementation(() => zipUploadStream)
|
|
72
|
+
crypto.createHash.mockImplementation(() => hashStream)
|
|
73
|
+
fs.createWriteStream.mockImplementation(() => writeStream)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
jest.resetAllMocks()
|
|
78
|
+
|
|
79
|
+
// Unset environment variables
|
|
80
|
+
delete process.env.LOCAL_ACTION_ARTIFACT_PATH
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('uploadArtifact', () => {
|
|
84
|
+
it('Uploads an artifact', async () => {
|
|
85
|
+
await uploadArtifact.uploadArtifact(
|
|
86
|
+
'artifact-name',
|
|
87
|
+
['file1', 'file2'],
|
|
88
|
+
'root'
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
expect(getUploadZipSpecification).toHaveBeenCalledTimes(1)
|
|
92
|
+
expect(createZipUploadStream).toHaveBeenCalledTimes(1)
|
|
93
|
+
expect(fs.createWriteStream).toHaveBeenCalledTimes(1)
|
|
94
|
+
expect(crypto.createHash).toHaveBeenCalledTimes(1)
|
|
95
|
+
expect(stream.finished).toHaveBeenCalledTimes(1)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('Throws if no files are included in the artifact', async () => {
|
|
99
|
+
getUploadZipSpecification.mockImplementation(() => [])
|
|
100
|
+
|
|
101
|
+
await expect(
|
|
102
|
+
uploadArtifact.uploadArtifact('artifact-name', [], 'root')
|
|
103
|
+
).rejects.toThrow()
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('Throws if an artifact exists with the same name', async () => {
|
|
107
|
+
EnvMeta.artifacts = [{ name: 'artifact-name', id: 1, size: 0 }]
|
|
108
|
+
|
|
109
|
+
await expect(
|
|
110
|
+
uploadArtifact.uploadArtifact('artifact-name', ['file'], 'root')
|
|
111
|
+
).rejects.toThrow()
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('Throws if more than 10 artifacts are created', async () => {
|
|
115
|
+
EnvMeta.artifacts = Array.from({ length: 10 }, (_, i) => ({
|
|
116
|
+
name: `artifact-${i}`,
|
|
117
|
+
id: i + 1,
|
|
118
|
+
size: 0
|
|
119
|
+
}))
|
|
120
|
+
|
|
121
|
+
await expect(
|
|
122
|
+
uploadArtifact.uploadArtifact('new-artifact', ['file'], 'root')
|
|
123
|
+
).rejects.toThrow()
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import * as core from '../../../../../__fixtures__/@actions/core.js'
|
|
3
|
+
import * as fs from '../../../../../__fixtures__/fs.js'
|
|
4
|
+
|
|
5
|
+
jest.unstable_mockModule('fs', () => fs)
|
|
6
|
+
jest.unstable_mockModule('../../../../../src/stubs/core/core.js', () => core)
|
|
7
|
+
|
|
8
|
+
const uploadZipSpecification =
|
|
9
|
+
await import('../../../../../src/stubs/artifact/internal/upload/upload-zip-specification.js')
|
|
10
|
+
|
|
11
|
+
describe('upload-zip-specification', () => {
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
jest.resetAllMocks()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('validateRootDirectory', () => {
|
|
17
|
+
it('Throws if the directory does not exist', () => {
|
|
18
|
+
fs.existsSync.mockReturnValue(false)
|
|
19
|
+
|
|
20
|
+
expect(() =>
|
|
21
|
+
uploadZipSpecification.validateRootDirectory('/invalid/path')
|
|
22
|
+
).toThrow('The provided rootDirectory /invalid/path does not exist')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('Throws if the path is not a directory', () => {
|
|
26
|
+
fs.existsSync.mockReturnValue(true)
|
|
27
|
+
fs.statSync.mockReturnValue({
|
|
28
|
+
isDirectory: () => false
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
expect(() =>
|
|
32
|
+
uploadZipSpecification.validateRootDirectory('/invalid/path')
|
|
33
|
+
).toThrow(
|
|
34
|
+
'The provided rootDirectory /invalid/path is not a valid directory'
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('Does not throw if the directory is valid', () => {
|
|
39
|
+
fs.existsSync.mockReturnValue(true)
|
|
40
|
+
fs.statSync.mockReturnValue({
|
|
41
|
+
isDirectory: () => true
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
expect(() =>
|
|
45
|
+
uploadZipSpecification.validateRootDirectory('/valid/path')
|
|
46
|
+
).not.toThrow()
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import * as core from '../../../__fixtures__/@actions/core.js'
|
|
3
|
+
import * as fs from '../../../__fixtures__/fs.js'
|
|
4
|
+
|
|
5
|
+
jest.unstable_mockModule('@actions/core', () => core)
|
|
6
|
+
jest.unstable_mockModule('fs', () => fs)
|
|
7
|
+
|
|
8
|
+
// Mock the internal dependencies
|
|
9
|
+
const mockTar = {
|
|
10
|
+
createTar: jest.fn() as jest.MockedFunction<any>,
|
|
11
|
+
extractTar: jest.fn() as jest.MockedFunction<any>,
|
|
12
|
+
listTar: jest.fn() as jest.MockedFunction<any>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
jest.unstable_mockModule(
|
|
16
|
+
'../../../src/stubs/cache/internal/tar.js',
|
|
17
|
+
() => mockTar
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
const mockUtils = {
|
|
21
|
+
createTempDirectory: jest.fn() as jest.MockedFunction<() => Promise<string>>,
|
|
22
|
+
getArchiveFileSizeInBytes: jest.fn() as jest.MockedFunction<
|
|
23
|
+
(path: string) => number
|
|
24
|
+
>,
|
|
25
|
+
getCacheFileName: jest.fn() as jest.MockedFunction<
|
|
26
|
+
(compression: string) => string
|
|
27
|
+
>,
|
|
28
|
+
getCacheVersion: jest.fn() as jest.MockedFunction<
|
|
29
|
+
(paths: string[], compression: string, crossOs: boolean) => string
|
|
30
|
+
>,
|
|
31
|
+
getCompressionMethod: jest.fn() as jest.MockedFunction<() => Promise<string>>,
|
|
32
|
+
resolvePaths: jest.fn() as jest.MockedFunction<
|
|
33
|
+
(paths: string[]) => Promise<string[]>
|
|
34
|
+
>,
|
|
35
|
+
unlinkFile: jest.fn() as jest.MockedFunction<(path: string) => Promise<void>>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
jest.unstable_mockModule(
|
|
39
|
+
'../../../src/stubs/cache/internal/cacheUtils.js',
|
|
40
|
+
() => mockUtils
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
// Mock env
|
|
44
|
+
const mockEnvMeta = {
|
|
45
|
+
caches: {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
jest.unstable_mockModule('../../../src/stubs/env.js', () => ({
|
|
49
|
+
EnvMeta: mockEnvMeta
|
|
50
|
+
}))
|
|
51
|
+
|
|
52
|
+
// Import after mocking
|
|
53
|
+
const { CACHE_STUBS, restoreCache, saveCache } =
|
|
54
|
+
await import('../../../src/stubs/cache/cache.js')
|
|
55
|
+
|
|
56
|
+
describe('cache/cache', () => {
|
|
57
|
+
const originalWorkspace = process.env.LOCAL_ACTION_WORKSPACE
|
|
58
|
+
const originalCachePath = process.env.LOCAL_ACTION_CACHE_PATH
|
|
59
|
+
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
jest.clearAllMocks()
|
|
62
|
+
|
|
63
|
+
process.env.LOCAL_ACTION_WORKSPACE = '/tmp/workspace'
|
|
64
|
+
process.env.LOCAL_ACTION_CACHE_PATH = '/tmp/cache'
|
|
65
|
+
|
|
66
|
+
// Reset default mocks
|
|
67
|
+
mockUtils.getArchiveFileSizeInBytes.mockReturnValue(1024 * 1024) // 1MB
|
|
68
|
+
mockUtils.getCacheFileName.mockReturnValue('cache.tgz')
|
|
69
|
+
mockUtils.getCacheVersion.mockReturnValue('abc123')
|
|
70
|
+
mockUtils.getCompressionMethod.mockResolvedValue('gzip')
|
|
71
|
+
mockUtils.resolvePaths.mockResolvedValue(['/path/to/files'])
|
|
72
|
+
mockUtils.createTempDirectory.mockResolvedValue('/tmp/archive')
|
|
73
|
+
mockUtils.unlinkFile.mockResolvedValue()
|
|
74
|
+
|
|
75
|
+
core.isDebug.mockReturnValue(false)
|
|
76
|
+
fs.readdirSync.mockReturnValue([])
|
|
77
|
+
fs.existsSync.mockReturnValue(false)
|
|
78
|
+
|
|
79
|
+
mockTar.createTar.mockResolvedValue(undefined)
|
|
80
|
+
mockTar.extractTar.mockResolvedValue(undefined)
|
|
81
|
+
mockTar.listTar.mockResolvedValue(undefined)
|
|
82
|
+
|
|
83
|
+
mockEnvMeta.caches = {}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
process.env.LOCAL_ACTION_WORKSPACE = originalWorkspace
|
|
88
|
+
process.env.LOCAL_ACTION_CACHE_PATH = originalCachePath
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('CACHE_STUBS', () => {
|
|
92
|
+
it('Exports the correct cache stub functions', () => {
|
|
93
|
+
expect(CACHE_STUBS).toHaveProperty('restoreCache')
|
|
94
|
+
expect(CACHE_STUBS).toHaveProperty('saveCache')
|
|
95
|
+
expect(typeof CACHE_STUBS.restoreCache).toBe('function')
|
|
96
|
+
expect(typeof CACHE_STUBS.saveCache).toBe('function')
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
describe('restoreCache', () => {
|
|
101
|
+
it('Throws if LOCAL_ACTION_WORKSPACE is not set', async () => {
|
|
102
|
+
delete process.env.LOCAL_ACTION_WORKSPACE
|
|
103
|
+
|
|
104
|
+
await expect(restoreCache(['src/'], 'cache-key')).rejects.toThrow(
|
|
105
|
+
'LOCAL_ACTION_WORKSPACE must be set when interacting with @actions/cache!'
|
|
106
|
+
)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('Throws if LOCAL_ACTION_CACHE_PATH is not set', async () => {
|
|
110
|
+
delete process.env.LOCAL_ACTION_CACHE_PATH
|
|
111
|
+
|
|
112
|
+
await expect(restoreCache(['src/'], 'cache-key')).rejects.toThrow(
|
|
113
|
+
'LOCAL_ACTION_CACHE_PATH must be set when interacting with @actions/cache!'
|
|
114
|
+
)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('Throws if no paths are provided', async () => {
|
|
118
|
+
await expect(restoreCache([], 'cache-key')).rejects.toThrow(
|
|
119
|
+
'Path Validation Error: At least one directory or file path is required'
|
|
120
|
+
)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('Throws if too many keys are provided', async () => {
|
|
124
|
+
const manyKeys = Array(11).fill('key')
|
|
125
|
+
|
|
126
|
+
await expect(
|
|
127
|
+
restoreCache(['src/'], 'primary-key', manyKeys)
|
|
128
|
+
).rejects.toThrow(
|
|
129
|
+
'Key Validation Error: Keys are limited to a maximum of 10.'
|
|
130
|
+
)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('Returns undefined if no cache is found', async () => {
|
|
134
|
+
fs.readdirSync.mockReturnValue([])
|
|
135
|
+
|
|
136
|
+
const result = await restoreCache(['src/'], 'cache-key')
|
|
137
|
+
|
|
138
|
+
expect(result).toBeUndefined()
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('Returns matched key for exact cache hit', async () => {
|
|
142
|
+
// Mock file system to return cache files - the key must match exactly
|
|
143
|
+
fs.readdirSync.mockReturnValue(['cache-key-abc123def456.cache'])
|
|
144
|
+
|
|
145
|
+
const result = await restoreCache(['src/'], 'cache-key')
|
|
146
|
+
|
|
147
|
+
expect(result).toBe('cache-key')
|
|
148
|
+
expect(core.info).toHaveBeenCalledWith('Cache hit for: cache-key')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('Handles undefined restore keys (nullish coalescing coverage)', async () => {
|
|
152
|
+
fs.readdirSync.mockReturnValue(['cache-key-abc123def456.cache'])
|
|
153
|
+
|
|
154
|
+
const result = await restoreCache(['src/'], 'cache-key', undefined)
|
|
155
|
+
|
|
156
|
+
expect(result).toBe('cache-key')
|
|
157
|
+
expect(core.info).toHaveBeenCalledWith('Cache hit for: cache-key')
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('Returns matched key for restore key hit', async () => {
|
|
161
|
+
// Mock file system to return cache files that match restore key
|
|
162
|
+
fs.readdirSync.mockReturnValue(['restore-key-abc123def456.cache'])
|
|
163
|
+
|
|
164
|
+
const result = await restoreCache(['src/'], 'primary-key', [
|
|
165
|
+
'restore-key'
|
|
166
|
+
])
|
|
167
|
+
|
|
168
|
+
expect(result).toBe('restore-key')
|
|
169
|
+
expect(core.info).toHaveBeenCalledWith(
|
|
170
|
+
'Cache hit for restore-key: restore-key'
|
|
171
|
+
)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('Handles lookup only option', async () => {
|
|
175
|
+
fs.readdirSync.mockReturnValue(['cache-key-abc123def456.cache'])
|
|
176
|
+
|
|
177
|
+
const result = await restoreCache(['src/'], 'cache-key', [], {
|
|
178
|
+
lookupOnly: true
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
expect(result).toBe('cache-key')
|
|
182
|
+
expect(core.info).toHaveBeenCalledWith('Lookup only - skipping download')
|
|
183
|
+
expect(mockTar.extractTar).not.toHaveBeenCalled()
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('Extracts cache when found', async () => {
|
|
187
|
+
fs.readdirSync.mockReturnValue(['cache-key-abc123def456.cache'])
|
|
188
|
+
|
|
189
|
+
const result = await restoreCache(['src/'], 'cache-key')
|
|
190
|
+
|
|
191
|
+
expect(result).toBe('cache-key')
|
|
192
|
+
expect(mockTar.extractTar).toHaveBeenCalled()
|
|
193
|
+
expect(core.info).toHaveBeenCalledWith('Cache restored successfully')
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('Lists tar contents in debug mode', async () => {
|
|
197
|
+
fs.readdirSync.mockReturnValue(['cache-key-abc123def456.cache'])
|
|
198
|
+
core.isDebug.mockReturnValue(true)
|
|
199
|
+
|
|
200
|
+
await restoreCache(['src/'], 'cache-key')
|
|
201
|
+
|
|
202
|
+
expect(mockTar.listTar).toHaveBeenCalled()
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('Handles errors during restoration', async () => {
|
|
206
|
+
fs.readdirSync.mockReturnValue(['cache-key-abc123def456.cache'])
|
|
207
|
+
mockTar.extractTar.mockRejectedValue(new Error('Extraction failed'))
|
|
208
|
+
|
|
209
|
+
const result = await restoreCache(['src/'], 'cache-key')
|
|
210
|
+
|
|
211
|
+
expect(result).toBeUndefined()
|
|
212
|
+
expect(core.warning).toHaveBeenCalledWith(
|
|
213
|
+
'Failed to restore: Extraction failed'
|
|
214
|
+
)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('Finds cache with partial key match', async () => {
|
|
218
|
+
// Reset to clean state and setup specific mock for this test
|
|
219
|
+
fs.readdirSync.mockReturnValue(['cache-key-extra-abc123def456.cache'])
|
|
220
|
+
|
|
221
|
+
const result = await restoreCache(['src/'], 'cache-key')
|
|
222
|
+
|
|
223
|
+
expect(result).toBe('cache-key')
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
describe('saveCache', () => {
|
|
228
|
+
beforeEach(() => {
|
|
229
|
+
mockEnvMeta.caches = { 1: 'existing-cache.cache' }
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('Throws if LOCAL_ACTION_WORKSPACE is not set', async () => {
|
|
233
|
+
delete process.env.LOCAL_ACTION_WORKSPACE
|
|
234
|
+
|
|
235
|
+
await expect(saveCache(['src/'], 'cache-key')).rejects.toThrow(
|
|
236
|
+
'LOCAL_ACTION_WORKSPACE must be set when interacting with @actions/cache!'
|
|
237
|
+
)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('Throws if LOCAL_ACTION_CACHE_PATH is not set', async () => {
|
|
241
|
+
delete process.env.LOCAL_ACTION_CACHE_PATH
|
|
242
|
+
|
|
243
|
+
await expect(saveCache(['src/'], 'cache-key')).rejects.toThrow(
|
|
244
|
+
'LOCAL_ACTION_CACHE_PATH must be set when interacting with @actions/cache!'
|
|
245
|
+
)
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it('Throws if no paths are provided', async () => {
|
|
249
|
+
await expect(saveCache([], 'cache-key')).rejects.toThrow(
|
|
250
|
+
'Path Validation Error: At least one directory or file path is required'
|
|
251
|
+
)
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it('Throws if key is too long', async () => {
|
|
255
|
+
const longKey = 'a'.repeat(513)
|
|
256
|
+
|
|
257
|
+
await expect(saveCache(['src/'], longKey)).rejects.toThrow(
|
|
258
|
+
`Key Validation Error: ${longKey} cannot be larger than 512 characters.`
|
|
259
|
+
)
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('Throws if key contains commas', async () => {
|
|
263
|
+
const invalidKey = 'cache,key'
|
|
264
|
+
|
|
265
|
+
await expect(saveCache(['src/'], invalidKey)).rejects.toThrow(
|
|
266
|
+
`Key Validation Error: ${invalidKey} cannot contain commas.`
|
|
267
|
+
)
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
it('Returns -1 if no paths resolve', async () => {
|
|
271
|
+
mockUtils.resolvePaths.mockResolvedValue([])
|
|
272
|
+
|
|
273
|
+
// The implementation throws an error when no paths resolve
|
|
274
|
+
await expect(saveCache(['src/'], 'cache-key')).rejects.toThrow(
|
|
275
|
+
'Path(s) specified in the action for caching do(es) not exist'
|
|
276
|
+
)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('Throws if cache already exists', async () => {
|
|
280
|
+
// Setup successful path resolution but existing cache
|
|
281
|
+
mockUtils.resolvePaths.mockResolvedValue(['/resolved/path'])
|
|
282
|
+
fs.existsSync.mockReturnValue(true)
|
|
283
|
+
|
|
284
|
+
const result = await saveCache(['src/'], 'cache-key')
|
|
285
|
+
|
|
286
|
+
// The implementation catches the error and returns -1
|
|
287
|
+
expect(result).toBe(-1)
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
it('Successfully saves cache', async () => {
|
|
291
|
+
// Setup successful path resolution and no existing cache
|
|
292
|
+
mockUtils.resolvePaths.mockResolvedValue(['/resolved/path'])
|
|
293
|
+
fs.existsSync.mockReturnValue(false)
|
|
294
|
+
|
|
295
|
+
const result = await saveCache(['src/'], 'cache-key')
|
|
296
|
+
|
|
297
|
+
expect(result).toBe(2) // Next ID after existing cache
|
|
298
|
+
expect(mockTar.createTar).toHaveBeenCalled()
|
|
299
|
+
expect(fs.copyFileSync).toHaveBeenCalled()
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
it('Lists tar contents in debug mode', async () => {
|
|
303
|
+
mockUtils.resolvePaths.mockResolvedValue(['/resolved/path'])
|
|
304
|
+
fs.existsSync.mockReturnValue(false)
|
|
305
|
+
core.isDebug.mockReturnValue(true)
|
|
306
|
+
|
|
307
|
+
await saveCache(['src/'], 'cache-key')
|
|
308
|
+
|
|
309
|
+
expect(mockTar.listTar).toHaveBeenCalled()
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
it('Handles errors during save', async () => {
|
|
313
|
+
mockUtils.resolvePaths.mockResolvedValue(['/resolved/path'])
|
|
314
|
+
fs.existsSync.mockReturnValue(false)
|
|
315
|
+
mockTar.createTar.mockRejectedValue(new Error('Create failed'))
|
|
316
|
+
|
|
317
|
+
const result = await saveCache(['src/'], 'cache-key')
|
|
318
|
+
|
|
319
|
+
expect(result).toBe(-1)
|
|
320
|
+
expect(core.warning).toHaveBeenCalledWith('Failed to save: Create failed')
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it('Cleans up archive file after save', async () => {
|
|
324
|
+
mockUtils.resolvePaths.mockResolvedValue(['/resolved/path'])
|
|
325
|
+
fs.existsSync.mockReturnValue(false)
|
|
326
|
+
|
|
327
|
+
await saveCache(['src/'], 'cache-key')
|
|
328
|
+
|
|
329
|
+
expect(mockUtils.unlinkFile).toHaveBeenCalled()
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
it('Handles archive cleanup errors', async () => {
|
|
333
|
+
mockUtils.resolvePaths.mockResolvedValue(['/resolved/path'])
|
|
334
|
+
fs.existsSync.mockReturnValue(false)
|
|
335
|
+
mockUtils.unlinkFile.mockRejectedValue(new Error('Cleanup failed'))
|
|
336
|
+
|
|
337
|
+
await saveCache(['src/'], 'cache-key')
|
|
338
|
+
|
|
339
|
+
expect(core.debug).toHaveBeenCalledWith(
|
|
340
|
+
'Failed to delete archive: Error: Cleanup failed'
|
|
341
|
+
)
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
it('Uses cross OS archive setting', async () => {
|
|
345
|
+
mockUtils.resolvePaths.mockResolvedValue(['/resolved/path'])
|
|
346
|
+
fs.existsSync.mockReturnValue(false)
|
|
347
|
+
|
|
348
|
+
await saveCache(['src/'], 'cache-key', {}, true)
|
|
349
|
+
|
|
350
|
+
expect(mockUtils.getCacheVersion).toHaveBeenCalledWith(
|
|
351
|
+
['src/'],
|
|
352
|
+
'gzip',
|
|
353
|
+
true
|
|
354
|
+
)
|
|
355
|
+
})
|
|
356
|
+
})
|
|
357
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InvalidResponseError,
|
|
3
|
+
ReserveCacheError,
|
|
4
|
+
ValidationError
|
|
5
|
+
} from '../../../src/stubs/cache/errors.js'
|
|
6
|
+
|
|
7
|
+
describe('cache/errors', () => {
|
|
8
|
+
describe('ValidationError', () => {
|
|
9
|
+
it('Creates a ValidationError with the correct message', () => {
|
|
10
|
+
const message = 'Test validation error'
|
|
11
|
+
const error = new ValidationError(message)
|
|
12
|
+
|
|
13
|
+
expect(error.message).toBe(message)
|
|
14
|
+
expect(error.name).toBe('ValidationError')
|
|
15
|
+
expect(error).toBeInstanceOf(ValidationError)
|
|
16
|
+
expect(error).toBeInstanceOf(Error)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('Sets the prototype correctly', () => {
|
|
20
|
+
const error = new ValidationError('test')
|
|
21
|
+
|
|
22
|
+
expect(Object.getPrototypeOf(error)).toBe(ValidationError.prototype)
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('ReserveCacheError', () => {
|
|
27
|
+
it('Creates a ReserveCacheError with the correct message', () => {
|
|
28
|
+
const message = 'Test reserve cache error'
|
|
29
|
+
const error = new ReserveCacheError(message)
|
|
30
|
+
|
|
31
|
+
expect(error.message).toBe(message)
|
|
32
|
+
expect(error.name).toBe('ReserveCacheError')
|
|
33
|
+
expect(error).toBeInstanceOf(ReserveCacheError)
|
|
34
|
+
expect(error).toBeInstanceOf(Error)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('Sets the prototype correctly', () => {
|
|
38
|
+
const error = new ReserveCacheError('test')
|
|
39
|
+
|
|
40
|
+
expect(Object.getPrototypeOf(error)).toBe(ReserveCacheError.prototype)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('InvalidResponseError', () => {
|
|
45
|
+
it('Creates an InvalidResponseError with the correct message', () => {
|
|
46
|
+
const message = 'Test invalid response error'
|
|
47
|
+
const error = new InvalidResponseError(message)
|
|
48
|
+
|
|
49
|
+
expect(error.message).toBe(message)
|
|
50
|
+
expect(error.name).toBe('InvalidResponseError')
|
|
51
|
+
expect(error).toBeInstanceOf(InvalidResponseError)
|
|
52
|
+
expect(error).toBeInstanceOf(Error)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
})
|