Restructure source and tests

This commit is contained in:
Nick Alteen 2023-09-14 10:36:27 -04:00
parent 570107f4a0
commit ea09560a8d
12 changed files with 294 additions and 94 deletions

18
__tests__/index.test.js Normal file
View File

@ -0,0 +1,18 @@
/**
* Unit tests for the action's entrypoint, src/index.ts
*/
const { run } = require('../src/main')
// Mock the action's entrypoint
jest.mock('../src/main', () => ({
run: jest.fn()
}))
describe('index', () => {
it('calls run when imported', async () => {
require('../src/index')
expect(run).toHaveBeenCalled()
})
})

100
__tests__/main.test.js Normal file
View File

@ -0,0 +1,100 @@
/**
* Unit tests for the action's main functionality, src/main.ts
*
* These should be run as if the action was called from a workflow.
* Specifically, the inputs listed in `action.yml` should be set as environment
* variables following the pattern `INPUT_<INPUT_NAME>`.
*/
const core = require('@actions/core')
const main = require('../src/main')
// Mock the GitHub Actions core library
const debugMock = jest.spyOn(core, 'debug').mockImplementation()
const getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
const setFailedMock = jest.spyOn(core, 'setFailed').mockImplementation()
const setOutputMock = jest.spyOn(core, 'setOutput').mockImplementation()
// Mock the action's main function
const runMock = jest.spyOn(main, 'run')
// Other utilities
const timeRegex = /^\d{2}:\d{2}:\d{2}/
describe('action', () => {
beforeEach(() => {
jest.clearAllMocks()
})
it('sets the time output', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock.mockImplementation(name => {
switch (name) {
case 'milliseconds':
return '500'
default:
return ''
}
})
await main.run()
expect(runMock).toHaveReturned()
// Verify that all of the core library functions were called correctly
expect(debugMock).toHaveBeenNthCalledWith(1, 'Waiting 500 milliseconds ...')
expect(debugMock).toHaveBeenNthCalledWith(
2,
expect.stringMatching(timeRegex)
)
expect(debugMock).toHaveBeenNthCalledWith(
3,
expect.stringMatching(timeRegex)
)
expect(setOutputMock).toHaveBeenNthCalledWith(
1,
'time',
expect.stringMatching(timeRegex)
)
})
it('sets a failed status', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock.mockImplementation(name => {
switch (name) {
case 'milliseconds':
return 'this is not a number'
default:
return ''
}
})
await main.run()
expect(runMock).toHaveReturned()
// Verify that all of the core library functions were called correctly
expect(setFailedMock).toHaveBeenNthCalledWith(
1,
'milliseconds not a number'
)
})
it('fails if no input is provided', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock.mockImplementation(name => {
switch (name) {
case 'milliseconds':
throw new Error('Input required and not supplied: milliseconds')
default:
return ''
}
})
await main.run()
expect(runMock).toHaveReturned()
// Verify that all of the core library functions were called correctly
expect(setFailedMock).toHaveBeenNthCalledWith(
1,
'Input required and not supplied: milliseconds'
)
})
})

24
__tests__/wait.test.js Normal file
View File

@ -0,0 +1,24 @@
/**
* Unit tests for src/wait.ts
*/
const { wait } = require('../src/wait')
const { expect } = require('@jest/globals')
describe('wait.ts', () => {
it('throws an invalid number', async () => {
const input = parseInt('foo', 10)
expect(isNaN(input)).toBe(true)
await expect(wait(input)).rejects.toThrow('milliseconds not a number')
})
it('waits with a valid number', async () => {
const start = new Date()
await wait(500)
const end = new Date()
const delta = Math.abs(end.getTime() - start.getTime())
expect(delta).toBeGreaterThan(450)
})
})

136
dist/index.js generated vendored
View File

@ -1,7 +1,7 @@
require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 351:
/***/ 241:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
@ -135,7 +135,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;
const command_1 = __nccwpck_require__(351);
const command_1 = __nccwpck_require__(241);
const file_command_1 = __nccwpck_require__(717);
const utils_1 = __nccwpck_require__(278);
const os = __importStar(__nccwpck_require__(37));
@ -558,7 +558,7 @@ class OidcClient {
.catch(error => {
throw new Error(`Failed to get ID Token. \n
Error Code : ${error.statusCode}\n
Error Message: ${error.result.message}`);
Error Message: ${error.message}`);
});
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
if (!id_token) {
@ -1211,6 +1211,19 @@ class HttpClientResponse {
}));
});
}
readBodyBuffer() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
const chunks = [];
this.message.on('data', (chunk) => {
chunks.push(chunk);
});
this.message.on('end', () => {
resolve(Buffer.concat(chunks));
});
}));
});
}
}
exports.HttpClientResponse = HttpClientResponse;
function isHttps(requestUrl) {
@ -1715,7 +1728,13 @@ function getProxyUrl(reqUrl) {
}
})();
if (proxyVar) {
return new URL(proxyVar);
try {
return new URL(proxyVar);
}
catch (_a) {
if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://'))
return new URL(`http://${proxyVar}`);
}
}
else {
return undefined;
@ -1726,6 +1745,10 @@ function checkBypass(reqUrl) {
if (!reqUrl.hostname) {
return false;
}
const reqHost = reqUrl.hostname;
if (isLoopbackAddress(reqHost)) {
return true;
}
const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
if (!noProxy) {
return false;
@ -1751,13 +1774,24 @@ function checkBypass(reqUrl) {
.split(',')
.map(x => x.trim().toUpperCase())
.filter(x => x)) {
if (upperReqHosts.some(x => x === upperNoProxyItem)) {
if (upperNoProxyItem === '*' ||
upperReqHosts.some(x => x === upperNoProxyItem ||
x.endsWith(`.${upperNoProxyItem}`) ||
(upperNoProxyItem.startsWith('.') &&
x.endsWith(`${upperNoProxyItem}`)))) {
return true;
}
}
return false;
}
exports.checkBypass = checkBypass;
function isLoopbackAddress(host) {
const hostLower = host.toLowerCase();
return (hostLower === 'localhost' ||
hostLower.startsWith('127.') ||
hostLower.startsWith('[::1]') ||
hostLower.startsWith('[0:0:0:0:0:0:0:1]'));
}
//# sourceMappingURL=proxy.js.map
/***/ }),
@ -2688,19 +2722,63 @@ exports["default"] = _default;
/***/ }),
/***/ 258:
/***/ 713:
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
const core = __nccwpck_require__(186)
const { wait } = __nccwpck_require__(312)
/**
* The main function for the action.
* @returns {Promise<void>} Resolves when the action is complete.
*/
async function run() {
try {
const ms = core.getInput('milliseconds', { required: true })
// Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
core.debug(`Waiting ${ms} milliseconds ...`)
// Log the current timestamp, wait, then log the new timestamp
core.debug(new Date().toTimeString())
await wait(parseInt(ms, 10))
core.debug(new Date().toTimeString())
// Set outputs for other workflow steps to use
core.setOutput('time', new Date().toTimeString())
} catch (error) {
// Fail the workflow run if an error occurs
core.setFailed(error.message)
}
}
module.exports = {
run
}
/***/ }),
/***/ 312:
/***/ ((module) => {
let wait = function (milliseconds) {
return new Promise((resolve) => {
if (typeof milliseconds !== 'number') {
throw new Error('milliseconds not a number');
/**
* Wait for a number of milliseconds.
*
* @param {number} milliseconds The number of milliseconds to wait.
* @returns {Promise<string>} Resolves with 'done!' after the wait is over.
*/
async function wait(milliseconds) {
return new Promise(resolve => {
if (isNaN(milliseconds)) {
throw new Error('milliseconds not a number')
}
setTimeout(() => resolve("done!"), milliseconds)
});
};
module.exports = wait;
setTimeout(() => resolve('done!'), milliseconds)
})
}
module.exports = { wait }
/***/ }),
@ -2834,31 +2912,15 @@ module.exports = require("util");
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
const core = __nccwpck_require__(186);
const wait = __nccwpck_require__(258);
/**
* The entrypoint for the action.
*/
const { run } = __nccwpck_require__(713)
// most @actions toolkit packages have async methods
async function run() {
try {
const ms = core.getInput('milliseconds');
core.info(`Waiting ${ms} milliseconds ...`);
core.debug((new Date()).toTimeString()); // debug is only output if you set the secret `ACTIONS_RUNNER_DEBUG` to true
await wait(parseInt(ms));
core.info((new Date()).toTimeString());
core.setOutput('time', new Date().toTimeString());
} catch (error) {
core.setFailed(error.message);
}
}
run();
run()
})();
module.exports = __webpack_exports__;
/******/ })()
;
//# sourceMappingURL=index.js.map
;

1
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

1
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -1,21 +0,0 @@
const core = require('@actions/core');
const wait = require('./wait');
// most @actions toolkit packages have async methods
async function run() {
try {
const ms = core.getInput('milliseconds');
core.info(`Waiting ${ms} milliseconds ...`);
core.debug((new Date()).toTimeString()); // debug is only output if you set the secret `ACTIONS_RUNNER_DEBUG` to true
await wait(parseInt(ms));
core.info((new Date()).toTimeString());
core.setOutput('time', new Date().toTimeString());
} catch (error) {
core.setFailed(error.message);
}
}
run();

View File

@ -1,24 +0,0 @@
const wait = require('./wait');
const process = require('process');
const cp = require('child_process');
const path = require('path');
test('throws invalid number', async () => {
await expect(wait('foo')).rejects.toThrow('milliseconds not a number');
});
test('wait 500 ms', async () => {
const start = new Date();
await wait(500);
const end = new Date();
var delta = Math.abs(end - start);
expect(delta).toBeGreaterThanOrEqual(500);
});
// shows how the runner will run a javascript action with env / stdout protocol
test('test runs', () => {
process.env['INPUT_MILLISECONDS'] = 100;
const ip = path.join(__dirname, 'index.js');
const result = cp.execSync(`node ${ip}`, {env: process.env}).toString();
console.log(result);
})

6
src/index.js Normal file
View File

@ -0,0 +1,6 @@
/**
* The entrypoint for the action.
*/
const { run } = require('./main')
run()

30
src/main.js Normal file
View File

@ -0,0 +1,30 @@
const core = require('@actions/core')
const { wait } = require('./wait')
/**
* The main function for the action.
* @returns {Promise<void>} Resolves when the action is complete.
*/
async function run() {
try {
const ms = core.getInput('milliseconds', { required: true })
// Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
core.debug(`Waiting ${ms} milliseconds ...`)
// Log the current timestamp, wait, then log the new timestamp
core.debug(new Date().toTimeString())
await wait(parseInt(ms, 10))
core.debug(new Date().toTimeString())
// Set outputs for other workflow steps to use
core.setOutput('time', new Date().toTimeString())
} catch (error) {
// Fail the workflow run if an error occurs
core.setFailed(error.message)
}
}
module.exports = {
run
}

17
src/wait.js Normal file
View File

@ -0,0 +1,17 @@
/**
* Wait for a number of milliseconds.
*
* @param {number} milliseconds The number of milliseconds to wait.
* @returns {Promise<string>} Resolves with 'done!' after the wait is over.
*/
async function wait(milliseconds) {
return new Promise(resolve => {
if (isNaN(milliseconds)) {
throw new Error('milliseconds not a number')
}
setTimeout(() => resolve('done!'), milliseconds)
})
}
module.exports = { wait }

10
wait.js
View File

@ -1,10 +0,0 @@
let wait = function (milliseconds) {
return new Promise((resolve) => {
if (typeof milliseconds !== 'number') {
throw new Error('milliseconds not a number');
}
setTimeout(() => resolve("done!"), milliseconds)
});
};
module.exports = wait;