1
0
Files
setup-dotnet/__tests__/setup-dotnet.test.ts
T
Priya Gupta 6df8cefd14 Migrate to ESM and upgrade dependencies (#752)
* Migrate to ESM and upgrade dependencies

* Address review: use type-only import for QualityOptions

* update version to 6.0.0 in package.json and package-lock.json

* Add ESM migration note to README for V6

* Update test imports for ESM and clean up devDependencies (ts-node, @types/jest)

* Pin @types/node to 24.x and refine tsconfig/README wording
2026-07-15 15:41:57 -05:00

394 lines
14 KiB
TypeScript

import {
afterEach,
beforeEach,
describe,
expect,
it,
jest,
test
} from '@jest/globals';
import semver from 'semver';
import os from 'os';
jest.unstable_mockModule('@actions/core', () => ({
getInput: jest.fn(),
getMultilineInput: jest.fn(),
getBooleanInput: jest.fn(),
setFailed: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
info: jest.fn(),
setOutput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn()
}));
jest.unstable_mockModule('fs', () => {
const actual = jest.requireActual('fs') as typeof import('fs');
const existsSync = jest.fn(actual.existsSync);
const readFileSync = jest.fn(actual.readFileSync);
return {
...actual,
existsSync,
readFileSync,
default: {...actual, existsSync, readFileSync}
};
});
jest.unstable_mockModule('../src/authutil', () => ({
configAuthentication: jest.fn()
}));
jest.unstable_mockModule('../src/cache-utils', () => ({
isCacheFeatureAvailable: jest.fn(),
getNuGetFolderPath: jest.fn()
}));
jest.unstable_mockModule('../src/cache-restore', () => ({
restoreCache: jest.fn()
}));
const core = await import('@actions/core');
const fs = await import('fs');
const auth = await import('../src/authutil.js');
const cacheUtils = await import('../src/cache-utils.js');
const cacheRestore = await import('../src/cache-restore.js');
const setup = await import('../src/setup-dotnet.js');
const {DotnetCoreInstaller, DotnetInstallDir} =
await import('../src/installer.js');
describe('setup-dotnet tests', () => {
const inputs = {} as any;
const getInputSpy = core.getInput as jest.Mock;
const getMultilineInputSpy = core.getMultilineInput as jest.Mock;
const getBooleanInputSpy = core.getBooleanInput as jest.Mock;
const setFailedSpy = core.setFailed as jest.Mock;
const warningSpy = core.warning as jest.Mock;
const debugSpy = core.debug as jest.Mock;
const infoSpy = core.info as jest.Mock;
const setOutputSpy = core.setOutput as jest.Mock;
const existsSyncSpy = fs.existsSync as jest.Mock;
const maxSatisfyingSpy = jest.spyOn(semver, 'maxSatisfying');
const installDotnetSpy = jest.spyOn(
DotnetCoreInstaller.prototype,
'installDotnet'
);
const isCacheFeatureAvailableSpy =
cacheUtils.isCacheFeatureAvailable as jest.Mock;
const restoreCacheSpy = cacheRestore.restoreCache as jest.Mock;
const configAuthenticationSpy = auth.configAuthentication as jest.Mock;
const addToPathOriginal = DotnetInstallDir.addToPath;
describe('run() tests', () => {
beforeEach(() => {
DotnetInstallDir.addToPath = jest.fn();
getMultilineInputSpy.mockImplementation(input => inputs[input as string]);
getInputSpy.mockImplementation(input => inputs[input as string]);
getBooleanInputSpy.mockImplementation(input => inputs[input as string]);
});
afterEach(() => {
DotnetInstallDir.addToPath = addToPathOriginal;
jest.clearAllMocks();
jest.resetAllMocks();
});
it('should fail the action if global-json-file input is present, but the file does not exist in the file system', async () => {
inputs['global-json-file'] = 'fictitious.json';
inputs['dotnet-version'] = [];
const expectedErrorMessage = `The specified global.json file '${inputs['global-json-file']}' does not exist`;
await setup.run();
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
});
test(`if 'dotnet-version' and 'global-json-file' inputs aren't present, should log into debug output, try to find global.json in the repo root, fail and log message into info output`, async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = [];
maxSatisfyingSpy.mockImplementation(() => null);
setOutputSpy.mockImplementation(() => {});
const expectedDebugMessage =
'No version found, trying to find version from global.json';
const expectedInfoMessage = `The global.json wasn't found in the root directory. No .NET version will be installed.`;
await setup.run();
expect(debugSpy).toHaveBeenCalledWith(expectedDebugMessage);
expect(existsSyncSpy).toHaveBeenCalled();
expect(infoSpy).toHaveBeenCalledWith(expectedInfoMessage);
});
it('should fail the action if quality is supplied but its value is not supported', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = ['10.0'];
inputs['dotnet-quality'] = 'fictitiousQuality';
const expectedErrorMessage = `Value '${inputs['dotnet-quality']}' is not supported for the 'dotnet-quality' option. Supported values are: daily, preview, ga.`;
await setup.run();
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
});
it('should call installDotnet() multiple times if dotnet-version multiline input is provided', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = ['9.0', '10.0'];
inputs['dotnet-quality'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(installDotnetSpy).toHaveBeenCalledTimes(2);
});
it('should call addToPath() after installation complete', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = ['9.0', '10.0'];
inputs['dotnet-quality'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(DotnetInstallDir.addToPath).toHaveBeenCalledTimes(1);
});
it('should call auth.configAuthentication() if source-url input is provided', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = [];
inputs['dotnet-quality'] = '';
inputs['source-url'] = 'fictitious.source.url';
configAuthenticationSpy.mockImplementation(() => {});
await setup.run();
expect(configAuthenticationSpy).toHaveBeenCalledWith(
inputs['source-url'],
undefined
);
});
it('should call auth.configAuthentication() with proper parameters if source-url and config-file inputs are provided', async () => {
inputs['global-json-file'] = '';
inputs['dotnet-version'] = [];
inputs['dotnet-quality'] = '';
inputs['source-url'] = 'fictitious.source.url';
inputs['config-file'] = 'fictitious.path';
configAuthenticationSpy.mockImplementation(() => {});
setOutputSpy.mockImplementation(() => {});
await setup.run();
expect(configAuthenticationSpy).toHaveBeenCalledWith(
inputs['source-url'],
inputs['config-file']
);
});
it('should call setOutput() after installation complete successfully', async () => {
inputs['dotnet-version'] = ['10.0.101'];
installDotnetSpy.mockImplementation(() =>
Promise.resolve(`${inputs['dotnet-version']}`)
);
await setup.run();
expect(DotnetInstallDir.addToPath).toHaveBeenCalledTimes(1);
});
it(`shouldn't call setOutput() if parsing dotnet-installer logs failed`, async () => {
inputs['dotnet-version'] = ['10.0.101'];
const warningMessage = `Failed to output the installed version of .NET. The 'dotnet-version' output will not be set.`;
installDotnetSpy.mockImplementation(() => Promise.resolve(null));
await setup.run();
expect(warningSpy).toHaveBeenCalledWith(warningMessage);
expect(setOutputSpy).not.toHaveBeenCalled();
});
it(`shouldn't call setOutput() if actions didn't install .NET`, async () => {
inputs['dotnet-version'] = [];
const warningMessage = `The 'dotnet-version' output will not be set.`;
await setup.run();
expect(infoSpy).toHaveBeenCalledWith(warningMessage);
expect(setOutputSpy).not.toHaveBeenCalled();
});
it(`should get 'cache-dependency-path' and call restoreCache() if input cache is set to true and cache feature is available`, async () => {
inputs['dotnet-version'] = ['10.0.101'];
inputs['dotnet-quality'] = '';
inputs['cache'] = true;
inputs['cache-dependency-path'] = 'fictitious.package.lock.json';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
isCacheFeatureAvailableSpy.mockImplementation(() => true);
restoreCacheSpy.mockImplementation(() => Promise.resolve());
await setup.run();
expect(isCacheFeatureAvailableSpy).toHaveBeenCalledTimes(1);
expect(restoreCacheSpy).toHaveBeenCalledWith(
inputs['cache-dependency-path']
);
});
it(`shouldn't call restoreCache() if input cache isn't set to true`, async () => {
inputs['dotnet-version'] = ['10.0.101'];
inputs['dotnet-quality'] = '';
inputs['cache'] = false;
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
isCacheFeatureAvailableSpy.mockImplementation(() => true);
restoreCacheSpy.mockImplementation(() => Promise.resolve());
await setup.run();
expect(restoreCacheSpy).not.toHaveBeenCalled();
});
it(`shouldn't call restoreCache() if cache feature isn't available`, async () => {
inputs['dotnet-version'] = ['10.0.101'];
inputs['dotnet-quality'] = '';
inputs['cache'] = true;
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
isCacheFeatureAvailableSpy.mockImplementation(() => false);
restoreCacheSpy.mockImplementation(() => Promise.resolve());
await setup.run();
expect(restoreCacheSpy).not.toHaveBeenCalled();
});
it('should pass valid architecture input to DotnetCoreInstaller', async () => {
inputs['dotnet-version'] = ['10.0.101'];
inputs['dotnet-quality'] = '';
inputs['architecture'] = os.arch().toLowerCase();
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(installDotnetSpy).toHaveBeenCalledTimes(1);
expect(DotnetInstallDir.addToPath).toHaveBeenCalledTimes(1);
});
it('should work with empty architecture input for auto-detection', async () => {
inputs['dotnet-version'] = ['10.0.101'];
inputs['dotnet-quality'] = '';
inputs['architecture'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(installDotnetSpy).toHaveBeenCalledTimes(1);
expect(DotnetInstallDir.addToPath).toHaveBeenCalledTimes(1);
});
it('should fail the action if unsupported architecture is provided', async () => {
inputs['dotnet-version'] = ['10.0.101'];
inputs['dotnet-quality'] = '';
inputs['architecture'] = 'x688';
const expectedErrorMessage = `Value 'x688' is not supported for the 'architecture' option. Supported values are: x64, x86, arm64, amd64, arm, s390x, ppc64le, riscv64.`;
await setup.run();
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
});
it('should fail the action if unsupported dotnet-channel value is provided with latest', async () => {
inputs['dotnet-version'] = ['latest'];
inputs['dotnet-quality'] = '';
inputs['dotnet-channel'] = 'invalid';
inputs['architecture'] = '';
const expectedErrorMessage = `Value 'invalid' is not supported for the 'dotnet-channel' option. Supported values are: LTS, STS, A.B (e.g. 8.0), A.B.Cxx (e.g. 8.0.1xx).`;
await setup.run();
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
});
it('should warn but not fail if unsupported dotnet-channel value is provided with a specific version', async () => {
inputs['dotnet-version'] = ['8.0.x'];
inputs['dotnet-quality'] = '';
inputs['dotnet-channel'] = 'invalid';
inputs['architecture'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(setFailedSpy).not.toHaveBeenCalled();
expect(warningSpy).toHaveBeenCalledWith(
`Value 'invalid' is not supported for the 'dotnet-channel' option and will be ignored because 'dotnet-version' is not set to 'latest'. Supported values are: LTS, STS, A.B (e.g. 8.0), A.B.Cxx (e.g. 8.0.1xx).`
);
});
it('should pass valid dotnet-channel value through without error', async () => {
inputs['dotnet-version'] = ['latest'];
inputs['dotnet-quality'] = '';
inputs['dotnet-channel'] = 'LTS';
inputs['architecture'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('should pass A.B channel value through without error when used with latest', async () => {
inputs['dotnet-version'] = ['latest'];
inputs['dotnet-quality'] = '';
inputs['dotnet-channel'] = '8.0';
inputs['architecture'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('should pass A.B.Cxx channel value through without error when used with latest', async () => {
inputs['dotnet-version'] = ['latest'];
inputs['dotnet-quality'] = '';
inputs['dotnet-channel'] = '8.0.1xx';
inputs['architecture'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('should fail with A.B.Cxx channel if major version is below 5', async () => {
inputs['dotnet-version'] = ['latest'];
inputs['dotnet-quality'] = '';
inputs['dotnet-channel'] = '3.1.1xx';
inputs['architecture'] = '';
const expectedErrorMessage = `Value '3.1.1xx' is not supported for the 'dotnet-channel' option. Supported values are: LTS, STS, A.B (e.g. 8.0), A.B.Cxx (e.g. 8.0.1xx).`;
await setup.run();
expect(setFailedSpy).toHaveBeenCalledWith(expectedErrorMessage);
});
it('should warn and not fail if valid dotnet-channel is provided with a non-latest version', async () => {
inputs['dotnet-version'] = ['8.0.x'];
inputs['dotnet-quality'] = '';
inputs['dotnet-channel'] = 'LTS';
inputs['architecture'] = '';
installDotnetSpy.mockImplementation(() => Promise.resolve(''));
await setup.run();
expect(setFailedSpy).not.toHaveBeenCalled();
expect(warningSpy).toHaveBeenCalledWith(
`The 'dotnet-channel' input is only supported when 'dotnet-version' is set to 'latest'.`
);
});
});
});