Skip to content

Commit f1fe877

Browse files
authored
refactor: use boolean input instead of manual conversion (#127)
* refactor: use boolean input instead of manual conversion * refactor: update setup test with less manual mocks * chore: upgrade to latest actions core version * fix: clean up the mock input util * chore: rebuild from macos * fix: add text to gitattributes * chore: remove built files * chore: add build files back
1 parent ff2ff0f commit f1fe877

11 files changed

Lines changed: 87 additions & 143 deletions

File tree

.gitattributes

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
* text=auto
44

55
# These files are text and should be normalized (Convert crlf => lf)
6-
build/** eol=lf
6+
build/** text eol=lf

build/setup/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/setup/index.map.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** @type {import('@jest/types').Config.InitialOptions} */
12
module.exports = {
23
verbose: true,
34
clearMocks: true,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
},
2424
"dependencies": {
2525
"@actions/cache": "^1.0.7",
26-
"@actions/core": "^1.4.0",
26+
"@actions/core": "^1.6.0",
2727
"@actions/exec": "^1.1.0",
2828
"@actions/io": "^1.1.1",
2929
"@actions/tool-cache": "^1.7.1",

src/actions/setup.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addPath, getInput, group, info } from '@actions/core';
1+
import { addPath, getBooleanInput, getInput, group, info } from '@actions/core';
22

33
import { install } from '../install';
44
import * as tools from '../tools';
@@ -19,7 +19,7 @@ export async function setupAction(): Promise<void> {
1919
})
2020
);
2121

22-
if (tools.getBoolean(getInput('patch-watchers'), true)) {
22+
if (!getInput('patch-watchers') || getBooleanInput('patch-watchers') !== false) {
2323
await group('Patching system watchers for the `ENOSPC` error', () => tools.maybePatchWatchers());
2424
}
2525
}
@@ -34,7 +34,7 @@ async function installCli(name: tools.PackageName): Promise<string | void> {
3434
}
3535

3636
const version = await tools.resolveVersion(name, inputVersion);
37-
const cache = tools.getBoolean(getInput(`${shortName}-cache`), false);
37+
const cache = getBooleanInput(`${shortName}-cache`);
3838

3939
try {
4040
const path = await group(

src/tools.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@ export type AuthenticateOptions = {
1414
password?: string;
1515
};
1616

17-
/**
18-
* Get a boolean value from string, useful for GitHub Actions boolean inputs.
19-
*/
20-
export function getBoolean(value: string, defaultValue = false): boolean {
21-
return (value || String(defaultValue)).toLowerCase() === 'true';
22-
}
23-
2417
/**
2518
* Convert `expo-cli` or `eas-cli` to just their binary name.
2619
* For windows we have to use `<bin>.cmd`, toolkit will handle the Windows binary with that.

tests/actions/setup.test.ts

Lines changed: 59 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,71 @@
1-
import { getToolsMock } from '../utils';
2-
3-
const core = {
4-
addPath: jest.fn(),
5-
getInput: jest.fn(),
6-
group: <T>(message: string, action: () => Promise<T>): Promise<T> => action(),
7-
info: jest.fn(),
8-
};
9-
const exec = { exec: jest.fn() };
10-
const install = { install: jest.fn() };
11-
const tools = getToolsMock();
12-
13-
jest.mock('@actions/core', () => core);
14-
jest.mock('@actions/exec', () => exec);
15-
jest.mock('../../src/tools', () => tools);
16-
jest.mock('../../src/install', () => install);
1+
import { getToolsMock, mockInput } from '../utils';
172

3+
jest.mock('../../src/tools', () => getToolsMock());
4+
5+
import * as core from '@actions/core';
6+
7+
import * as install from '../../src/install';
8+
import * as tools from '../../src/tools';
189
import { setupAction } from '../../src/actions/setup';
1910

20-
describe('run', () => {
21-
it('patches the system when set to true', async () => {
22-
mockInput({ patchWatchers: 'true' });
23-
await setupAction();
24-
expect(tools.maybePatchWatchers).toHaveBeenCalled();
25-
});
11+
describe(setupAction, () => {
12+
describe('patch watchers', () => {
13+
it('patches the system when set to true', async () => {
14+
mockInput({ 'patch-watchers': 'true' });
15+
await setupAction();
16+
expect(tools.maybePatchWatchers).toHaveBeenCalled();
17+
});
2618

27-
it('patches the system when not set', async () => {
28-
mockInput({ patchWatchers: '' });
29-
await setupAction();
30-
expect(tools.maybePatchWatchers).toHaveBeenCalled();
31-
});
19+
it('patches the system when not set', async () => {
20+
mockInput({ 'patch-watchers': '' });
21+
await setupAction();
22+
expect(tools.maybePatchWatchers).toHaveBeenCalled();
23+
});
3224

33-
it('skips the system patch when set to false', async () => {
34-
mockInput({ patchWatchers: 'false' });
35-
await setupAction();
36-
expect(tools.maybePatchWatchers).not.toHaveBeenCalled();
25+
it('skips the system patch when set to false', async () => {
26+
mockInput({ 'patch-watchers': 'false' });
27+
await setupAction();
28+
expect(tools.maybePatchWatchers).not.toHaveBeenCalled();
29+
});
3730
});
3831

39-
it('authenticates with provided credentials', async () => {
40-
mockInput({ username: 'bycedric', password: 'mypassword', patchWatchers: 'false' });
41-
await setupAction();
42-
expect(tools.maybeAuthenticate).toBeCalledWith({ username: 'bycedric', password: 'mypassword' });
43-
});
32+
describe('authentication', () => {
33+
it('authenticates with provided credentials', async () => {
34+
mockInput({ username: 'bycedric', password: 'mypassword' });
35+
await setupAction();
36+
expect(tools.maybeAuthenticate).toBeCalledWith({ username: 'bycedric', password: 'mypassword' });
37+
});
4438

45-
it('authenticates with provided token', async () => {
46-
mockInput({ token: 'ABC123', patchWatchers: 'false' });
47-
await setupAction();
48-
expect(tools.maybeAuthenticate).toBeCalledWith({ token: 'ABC123' });
39+
it('authenticates with provided token', async () => {
40+
mockInput({ token: 'ABC123' });
41+
await setupAction();
42+
expect(tools.maybeAuthenticate).toBeCalledWith({ token: 'ABC123' });
43+
});
4944
});
5045

5146
['expo', 'eas'].forEach(cliName => {
5247
const packageName = `${cliName}-cli`;
48+
let installMock: jest.SpyInstance;
49+
50+
beforeEach(() => {
51+
installMock = jest.spyOn(install, 'install').mockImplementation();
52+
});
53+
54+
afterEach(() => {
55+
installMock.mockRestore();
56+
});
5357

5458
describe(packageName, () => {
5559
it(`skips installation without \`${cliName}-version\``, async () => {
5660
mockInput();
5761
await setupAction();
58-
expect(install.install).not.toBeCalledWith({ package: packageName });
62+
expect(installMock).not.toBeCalledWith({ package: packageName });
5963
});
6064

6165
it('installs with yarn by default', async () => {
62-
mockInput({ [`${cliName}Version`]: 'latest' });
66+
mockInput({ [`${cliName}-version`]: 'latest' });
6367
await setupAction();
64-
expect(install.install).toBeCalledWith({
68+
expect(installMock).toBeCalledWith({
6569
package: packageName,
6670
version: 'latest',
6771
packager: 'yarn',
@@ -70,9 +74,9 @@ describe('run', () => {
7074
});
7175

7276
it('installs provided version with npm', async () => {
73-
mockInput({ [`${cliName}Version`]: '3.0.10', packager: 'npm' });
77+
mockInput({ [`${cliName}-version`]: '3.0.10', packager: 'npm' });
7478
await setupAction();
75-
expect(install.install).toBeCalledWith({
79+
expect(installMock).toBeCalledWith({
7680
package: packageName,
7781
version: '3.0.10',
7882
packager: 'npm',
@@ -83,11 +87,11 @@ describe('run', () => {
8387
it('installs with yarn and cache enabled', async () => {
8488
mockInput({
8589
packager: 'yarn',
86-
[`${cliName}Version`]: '4.2.0',
87-
[`${cliName}Cache`]: 'true',
90+
[`${cliName}-version`]: '4.2.0',
91+
[`${cliName}-cache`]: 'true',
8892
});
8993
await setupAction();
90-
expect(install.install).toBeCalledWith({
94+
expect(installMock).toBeCalledWith({
9195
package: packageName,
9296
version: '4.2.0',
9397
packager: 'yarn',
@@ -98,12 +102,12 @@ describe('run', () => {
98102
it('installs with yarn and custom cache key', async () => {
99103
mockInput({
100104
packager: 'yarn',
101-
[`${cliName}Version`]: '4.2.0',
102-
[`${cliName}Cache`]: 'true',
103-
[`${cliName}CacheKey`]: 'custom-key',
105+
[`${cliName}-version`]: '4.2.0',
106+
[`${cliName}-cache`]: 'true',
107+
[`${cliName}-cache-key`]: 'custom-key',
104108
});
105109
await setupAction();
106-
expect(install.install).toBeCalledWith({
110+
expect(installMock).toBeCalledWith({
107111
package: packageName,
108112
version: '4.2.0',
109113
packager: 'yarn',
@@ -113,59 +117,11 @@ describe('run', () => {
113117
});
114118

115119
it('installs path to global path', async () => {
116-
install.install.mockResolvedValue(`/${cliName}/install/path`);
120+
installMock.mockResolvedValue(`/${cliName}/install/path`);
121+
const addPathSpy = jest.spyOn(core, 'addPath').mockImplementation();
117122
await setupAction();
118-
expect(core.addPath).toBeCalledWith(`/${cliName}/install/path`);
123+
expect(addPathSpy).toBeCalledWith(`/${cliName}/install/path`);
119124
});
120125
});
121126
});
122127
});
123-
124-
interface MockInputProps {
125-
expoVersion?: string;
126-
expoCache?: string;
127-
expoCacheKey?: string;
128-
easVersion?: string;
129-
easCache?: string;
130-
easCacheKey?: string;
131-
packager?: string;
132-
token?: string;
133-
username?: string;
134-
password?: string;
135-
patchWatchers?: string;
136-
}
137-
138-
function mockInput(props: MockInputProps = {}) {
139-
// fix: kind of dirty workaround for missing "mock 'value' based on arguments"
140-
const input = (name: string) => {
141-
switch (name) {
142-
case 'expo-version':
143-
return props.expoVersion || '';
144-
case 'expo-cache':
145-
return props.expoCache || '';
146-
case 'expo-cache-key':
147-
return props.expoCacheKey || '';
148-
case 'eas-version':
149-
return props.easVersion || '';
150-
case 'eas-cache':
151-
return props.easCache || '';
152-
case 'eas-cache-key':
153-
return props.easCacheKey || '';
154-
case 'packager':
155-
return props.packager || '';
156-
case 'token':
157-
return props.token || '';
158-
case 'username':
159-
return props.username || '';
160-
case 'password':
161-
return props.password || '';
162-
case 'patch-watchers':
163-
return props.patchWatchers || '';
164-
default:
165-
return '';
166-
}
167-
};
168-
169-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
170-
core.getInput = input as any;
171-
}

tests/tools.test.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,6 @@ import * as cli from '@actions/exec';
77
import * as tools from '../src/tools';
88
import * as utils from './utils';
99

10-
describe(tools.getBoolean, () => {
11-
it('rreturns false for empty strings by default', () => {
12-
expect(tools.getBoolean('')).toBeFalsy();
13-
});
14-
15-
it('returns true for empty strings with default set to true', () => {
16-
expect(tools.getBoolean('', true)).toBeTruthy();
17-
});
18-
19-
it('returns true for `true` strings by default', () => {
20-
expect(tools.getBoolean('true')).toBeTruthy();
21-
});
22-
23-
it('returns false for `false` strings with default set to false', () => {
24-
expect(tools.getBoolean('false', false)).toBeFalsy();
25-
});
26-
27-
it('returns false for `false` strings with default set to true', () => {
28-
expect(tools.getBoolean('false', true)).toBeFalsy();
29-
});
30-
});
31-
3210
describe(tools.getBinaryName, () => {
3311
it('returns expo for `expo-cli`', () => {
3412
expect(tools.getBinaryName('expo-cli')).toBe('expo');

tests/utils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import * as core from '@actions/core';
2+
13
// keep track of the original one to revert the platform
24
const originalPlatform = process.platform;
35

@@ -38,7 +40,6 @@ export function restoreEnv(): void {
3840
*/
3941
export function getToolsMock() {
4042
return {
41-
getBoolean: jest.fn((v, d) => (v ? v === 'true' : d)),
4243
getBinaryName: jest.fn(v => v.replace('-cli', '')),
4344
resolveVersion: jest.fn((n, v) => v),
4445
maybeAuthenticate: jest.fn(),
@@ -48,3 +49,11 @@ export function getToolsMock() {
4849
performAction: jest.fn(),
4950
};
5051
}
52+
53+
/**
54+
* Mock both the input and boolean input methods from `@actions/core`.
55+
*/
56+
export function mockInput(inputs: Record<string, string> = {}) {
57+
jest.spyOn(core, 'getInput').mockImplementation(name => inputs[name]);
58+
jest.spyOn(core, 'getBooleanInput').mockImplementation(name => inputs[name] === 'true');
59+
}

0 commit comments

Comments
 (0)