From dd31d0220fdc9e6eb3469b3443239359d7da33d4 Mon Sep 17 00:00:00 2001 From: Bryan Killian Date: Thu, 19 Mar 2020 05:31:44 -0400 Subject: [PATCH] fix(everything): very proud to say this is 100% coverage according to default jest of all src code (including test) --- .eslintrc.yml | 21 +- README.md | 3 + jest.config.js | 3 +- package.json | 5 +- src/FilesHelper.ts | 15 +- src/GithubHelper.ts | 32 +- src/InputHelper.ts | 9 +- src/UtilsHelper.ts | 30 +- src/main.ts | 50 ++-- src/tests/FilesHelper.test.ts | 174 ++++++++--- src/tests/GithubHelper.test.ts | 142 ++++++--- src/tests/InputHelper.test.ts | 281 ++++++++++-------- src/tests/UtilsHelper.test.ts | 58 +++- src/tests/main.test.ts | 51 +++- src/tests/mocks/core/index.test.ts | 54 ++++ src/tests/mocks/core/index.ts | 33 ++ src/tests/mocks/env/env.test.ts | 80 ----- src/tests/mocks/env/index.test.ts | 148 +++++++++ src/tests/mocks/env/index.ts | 126 ++++---- src/tests/mocks/env/payloads.ts | 221 -------------- src/tests/mocks/fs/index.test.ts | 23 ++ src/tests/mocks/fs/index.ts | 14 + src/tests/mocks/github/index.test.ts | 29 ++ src/tests/mocks/github/index.ts | 23 ++ .../mocks/octokit/endpoint/merge.test.ts | 45 +++ src/tests/mocks/octokit/endpoint/merge.ts | 13 +- src/tests/mocks/octokit/index.test.ts | 11 + src/tests/mocks/octokit/paginate.test.ts | 51 ++++ .../mocks/octokit/pulls/listFiles.test.ts | 18 ++ src/tests/mocks/octokit/pulls/listFiles.ts | 1 - .../octokit/repos/compareCommits.test.ts | 18 ++ .../mocks/octokit/repos/compareCommits.ts | 1 - src/tests/payloads.ts | 232 +++++++++++++++ src/typings/CoreMock/index.d.ts | 11 + src/typings/FsMock/index.d.ts | 10 + src/typings/GitHubMock/index.d.ts | 7 + src/typings/OctokitMock/index.d.ts | 2 +- src/typings/TestInput/index.d.ts | 4 +- tsconfig.build.json | 6 + tsconfig.json | 3 - yarn.lock | 103 ++++++- 41 files changed, 1493 insertions(+), 668 deletions(-) create mode 100644 src/tests/mocks/core/index.test.ts create mode 100644 src/tests/mocks/core/index.ts delete mode 100644 src/tests/mocks/env/env.test.ts create mode 100644 src/tests/mocks/env/index.test.ts delete mode 100644 src/tests/mocks/env/payloads.ts create mode 100644 src/tests/mocks/fs/index.test.ts create mode 100644 src/tests/mocks/fs/index.ts create mode 100644 src/tests/mocks/github/index.test.ts create mode 100644 src/tests/mocks/github/index.ts create mode 100644 src/tests/mocks/octokit/endpoint/merge.test.ts create mode 100644 src/tests/mocks/octokit/index.test.ts create mode 100644 src/tests/mocks/octokit/paginate.test.ts create mode 100644 src/tests/mocks/octokit/pulls/listFiles.test.ts create mode 100644 src/tests/mocks/octokit/repos/compareCommits.test.ts create mode 100644 src/tests/payloads.ts create mode 100644 src/typings/CoreMock/index.d.ts create mode 100644 src/typings/FsMock/index.d.ts create mode 100644 src/typings/GitHubMock/index.d.ts create mode 100644 tsconfig.build.json diff --git a/.eslintrc.yml b/.eslintrc.yml index 5ddab6d3..a66a72bb 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,14 +1,12 @@ plugins: - '@typescript-eslint' - eslint-comments - - jest - promise - unicorn extends: - airbnb-typescript - plugin:@typescript-eslint/recommended - plugin:eslint-comments/recommended - - plugin:jest/recommended - plugin:promise/recommended - plugin:unicorn/recommended - prettier @@ -23,8 +21,10 @@ settings: typescript: {} rules: unicorn/filename-case: off + react/static-property-placement: 0 no-prototype-builtins: 0 import/prefer-default-export: 0 + '@typescript-eslint/no-explicit-any': 0 import/no-default-export: error no-use-before-define: - error @@ -37,8 +37,6 @@ rules: - allowExpressions: true allowTypedFunctionExpressions: true - '@typescript-eslint/no-explicit-any': - - off '@typescript-eslint/no-use-before-define': - error - @@ -57,5 +55,16 @@ parserOptions: sourceType: module env: node: true - jest: true - browser: true \ No newline at end of file + browser: true +overrides: + - files: ['src/tests/**/*'] + plugins: + - jest + extends: + - plugin:jest/recommended + rules: + global-require: 0 + '@typescript-eslint/no-var-requires': 0 + no-console: 0 + '@typescript-eslint/no-unused-vars': 0 + '@typescript-eslint/no-throw-literal': 0 diff --git a/README.md b/README.md index 6e5ecd1d..4b68e55e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # file-changes-action +[![codecov](https://codecov.io/gh/trilom/file-changes-action/branch/master/graph/badge.svg)](https://codecov.io/gh/trilom/file-changes-action) +![Integration Tests](https://github.com/trilom/file-changes-action/workflows/Integration%20Tests/badge.svg) + This action will take the information from the Push/Pull Request and output some variables and write files that will let you know what was changed, removed, or added. ## Inputs diff --git a/jest.config.js b/jest.config.js index 76794866..0f98d148 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,8 +2,9 @@ module.exports = { preset: 'ts-jest', testEnvironment: "node", testRunner: 'jest-circus/runner', + testMatch: ['**/*.test.ts'], clearMocks: true, - collectCoverage: true, + collectCoverage: false, coverageThreshold: { global: { branches: 50, diff --git a/package.json b/package.json index bd5bde17..64ee5fe1 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,9 @@ "main": "lib/main.js", "scripts": { "build": "yarn && tsc", - "build-package": "yarn build && ncc build", + "build-package": "yarn build --build tsconfig.build.json && ncc build", "build-release": "yarn build-package --minify", - "test": "jest --passWithNoTests", + "test": "jest", "test-coverage": "jest --coverage", "format": "prettier --write **/*.ts", "format-check": "prettier --check **/*.ts", @@ -44,6 +44,7 @@ "@typescript-eslint/eslint-plugin": "^2.24.0", "@typescript-eslint/parser": "^2.24.0", "@zeit/ncc": "^0.20.5", + "codecov": "^3.6.5", "eslint": "^6.8.0", "eslint-config-airbnb-typescript": "^7.0.0", "eslint-config-prettier": "^6.10.0", diff --git a/src/FilesHelper.ts b/src/FilesHelper.ts index 13af81ee..c4139dc3 100644 --- a/src/FilesHelper.ts +++ b/src/FilesHelper.ts @@ -1,7 +1,10 @@ +import { + setOutput as coreSetOutput, + debug as coreDebug +} from '@actions/core' import { writeFileSync } from 'fs' -import { setOutput as coreSetOutput, debug as coreDebug } from '@actions/core' import type {ChangedFiles} from 'typings/ChangedFiles' -import type { GitHubFile } from './typings/GitHubFile' +import type { GitHubFile } from 'typings/GitHubFile' import {getErrorString} from './UtilsHelper' /** @@ -19,8 +22,8 @@ export function sortChangedFiles(files: GitHubFile[]): ChangedFiles { }) return changedFiles } catch (error) { - const eString = `There was an issue sorting files changed files.` - throw new Error(getErrorString(error.name || 'unknown', error.status, sortChangedFiles.name, eString, JSON.stringify(error))) + const eString = `There was an issue sorting files changed.` + throw new Error(getErrorString(error.name, error.status, sortChangedFiles.name, eString, JSON.stringify(error))) } } @@ -78,7 +81,7 @@ export function writeFiles(format: string, key: string, files: string[]): void { ) } catch (error) { const eString = `There was an issue writing output files.` - throw new Error(getErrorString(error.name || 'unknown', error.status, writeFiles.name, eString, JSON.stringify(error))) + throw new Error(getErrorString(error.name, error.status, writeFiles.name, eString, JSON.stringify(error))) } } @@ -96,6 +99,6 @@ export function writeOutput(format: string, key: string, files: string[]): void coreSetOutput(fileName, formatChangedFiles(format, files)) } catch (error) { const eString = `There was an issue setting action outputs.` - throw new Error(getErrorString(error.name || 'unknown', error.status, writeOutput.name, eString, JSON.stringify(error))) + throw new Error(getErrorString(error.name, error.status, writeOutput.name, eString, JSON.stringify(error))) } } diff --git a/src/GithubHelper.ts b/src/GithubHelper.ts index 97003e7b..a48c47b5 100644 --- a/src/GithubHelper.ts +++ b/src/GithubHelper.ts @@ -1,7 +1,7 @@ -import {GitHub} from '@actions/github' +import { GitHub } from '@actions/github' +import type {GitHubFile} from 'typings/GitHubFile' +import type { Inferred } from "typings/Inferred" import { getErrorString } from './UtilsHelper' -import type { Inferred } from "./typings/Inferred" -import type {GitHubFile} from './typings/GitHubFile' /** * @function initClient * @throws {Error} not sure what might trigger this, but it will throw an error. @@ -14,8 +14,7 @@ export function initClient( try { return new GitHub(token) } catch (error) { - const eString = `There was an error creating github client. \ -Please check your token.` + const eString = `There was an error creating github client. Please check your token.` throw new Error(getErrorString(error.name, error.status, initClient.name, eString, error)) } } @@ -44,8 +43,7 @@ export async function getChangedPRFiles( ) return files } catch(error) { - const eString = `There was an error getting change files for -repo:${repo} owner:${owner} pr:${pullNumber}` + const eString = `There was an error getting change files for repo:${repo} owner:${owner} pr:${pullNumber}` let ePayload: string if (error.name === 'HttpError' && +error.status === 404) ePayload = getErrorString(error.name, error.status, getChangedPRFiles.name, eString, error) else ePayload = getErrorString(`Unknown Error:${error.name || ''}`, error.status, getChangedPRFiles.name, eString, error.message) @@ -79,8 +77,7 @@ export async function getChangedPushFiles( ) return files } catch (error) { - const eString = `There was an error getting change files for -repo:${repo} owner:${owner} base:${base} head:${head}` + const eString = `There was an error getting change files for repo:${repo} owner:${owner} base:${base} head:${head}` let ePayload: string if (error.name === 'HttpError' && +error.status === 404) ePayload = getErrorString(error.name, error.status, getChangedPushFiles.name, eString, error) else ePayload = getErrorString(`Unknown Error:${error.name || ''}`, error.status, getChangedPushFiles.name, eString, error.message) @@ -100,8 +97,9 @@ export async function getChangedFiles( { before, after, pr = NaN }: Inferred ): Promise { try { - if (repoFull.split('/').length > 2) - throw new Error(getErrorString(`Bad-Repo`, 500, getChangedFiles.name, `Repo input of ${repoFull} has more than 2 length after splitting.`)) + if (repoFull.split('/').length > 2) { + throw new Error(getErrorString(`Bad-Repo`, 500, 'self', `Repo input of ${repoFull} has more than 2 length after splitting.`)) + } const owner = repoFull.split('/')[0] const repo = repoFull.split('/')[1] let files:GitHubFile[] = [] @@ -114,9 +112,13 @@ export async function getChangedFiles( const pError = JSON.parse(error.message) if (pError.from.includes('getChanged')) throw new Error(JSON.stringify({ ...pError, ...{ from: `${error.status}/${error.name}`} }, null, 2)) - const eString = `There was an error getting change files outputs -pr: ${pr} before: ${before} after: ${after}` - const ePayload: string = getErrorString(`Unknown Error:${error.name || ''}`, error.status, getChangedFiles.name, eString, error.message) + const eString = `There was an error getting change files outputs pr: ${pr} before: ${before} after: ${after}` + const ePayload: string = getErrorString( + `Unknown Error:${error.name}`, + error.status, + getChangedFiles.name, + eString, + error.message) throw new Error(ePayload) } -} \ No newline at end of file +} diff --git a/src/InputHelper.ts b/src/InputHelper.ts index 2853381b..6c7afce9 100644 --- a/src/InputHelper.ts +++ b/src/InputHelper.ts @@ -1,10 +1,11 @@ import { warning as coreWarning, - getInput as coreGetInput } from '@actions/core' + getInput as coreGetInput +} from '@actions/core' import { context } from '@actions/github' +import type {Inferred} from 'typings/Inferred' +import type {Inputs} from 'typings/Inputs' import { getErrorString } from './UtilsHelper' -import {Inputs} from './typings/Inputs' -import {Inferred} from './typings/Inferred' /** * @function getInputs @@ -24,7 +25,7 @@ export function getInputs():Inputs { prNumber: +coreGetInput('prNumber') || ((typeof (context.issue.number) === 'undefined') ? NaN : context.issue.number), output: coreGetInput('output') || 'json', fileOutput: coreGetInput('fileOutput') || 'json', - event: context.eventName || 'push' + event: context.eventName } as Inputs } catch (error) { const eString = `Received an issue getting action inputs.` diff --git a/src/UtilsHelper.ts b/src/UtilsHelper.ts index 9cae4944..3684898c 100644 --- a/src/UtilsHelper.ts +++ b/src/UtilsHelper.ts @@ -1,7 +1,13 @@ import {setFailed} from '@actions/core' -import * as t from '@actions/core' -import {ActionError} from './typings/ActionError' - +import type {ActionError} from 'typings/ActionError' +/** + * @function getErrorString + * @param name name of error + * @param status status code of error + * @param from name of function that error is thrown from + * @param message error message + * @param error error object to stringify and attach + */ export function getErrorString( name: string, status = 500, @@ -21,4 +27,22 @@ export function getErrorString( setFailed(`Error throwing error.\n ${JSON.stringify(error_.message)}`) throw(new Error(JSON.stringify({name: '500/undefined', message: 'Error throwing error.'}))) } +} +/** + * @function errorMessage + * @param f name of function + * @param e error object + * @returns error message for function + */ +export function errorMessage (f:string, e:Error): string { + const error = JSON.stringify(e, null, 2) + let ret + if (f.includes('getInputs')) ret = `There was an getting action inputs.` + if (f.includes('inferInput')) ret = `There was an issue inferring inputs to the action.` + if (f.includes('initClient')) ret = `There was an issue initilizing the github client.` + if (f.includes('getChangedFiles')) ret = `There was an issue getting changed files from Github.` + if (f.includes('sortChangedFiles')) ret = `There was an issue sorting changed files from Github.` + if (f.includes('writeFiles')) ret = `There was an issue writing output files.` + if (f.includes('writeOutput')) ret = `There was an issue writing output variables.` + return `${ret}\nException: ${error}` } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index c5e5e9d1..3fc77c5a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,22 @@ -// External Dependencies -import {error as coreError, setFailed as coreSetFailed} from '@actions/core' -import {getInputs, inferInput} from './InputHelper' -import { writeOutput, writeFiles, sortChangedFiles} from './FilesHelper' -import { getChangedFiles, initClient} from './GithubHelper' - +import { + setFailed as coreSetFailed +} from '@actions/core' +import { + getInputs, + inferInput +} from './InputHelper' +import { + writeOutput, + writeFiles, + sortChangedFiles +} from './FilesHelper' +import { + getChangedFiles, + initClient +} from './GithubHelper' +import { + errorMessage +} from './UtilsHelper' // figure out if it is a PR or Push export async function run(): Promise { try { @@ -27,30 +40,7 @@ export async function run(): Promise { process.exit(0) } catch (error) { const pError = JSON.parse(error.message) - const prettyError = JSON.stringify(error.message, null, 2) - // catch error from getInputs - if (pError.from.includes(getInputs.name)) - coreError(`There was an getting action inputs.\nException: ${prettyError}`) - // catch error from inferInput - if (pError.from.includes(inferInput.name)) - coreError(`There was an issue inferring inputs to the action.\nException: ${prettyError}`) - // catch error from initClient - else if (pError.from.includes(initClient.name)) - coreError(`There was an issue initilizing the github client.\nException: ${prettyError}`) - // catch error from getChangedFiles - else if (pError.from.includes(getChangedFiles.name)) - coreError(`There was an issue getting changed files from Github.\nException: ${prettyError}`) - // catch error from sortChangedFiles - else if (pError.from.includes(sortChangedFiles.name)) - coreError(`There was an issue sorting changed files from Github.\nException: ${prettyError}`) - // catch error from writeFiles - else if (pError.from.includes(writeFiles.name)) - coreError(`There was an issue writing output files.\nException: ${prettyError}`) - // catch error from writeOutput - else if (pError.from.includes(writeOutput.name)) - coreError(`There was an issue writing output variables.\nException: ${prettyError}`) - else coreError(JSON.stringify(pError)) - coreSetFailed(error.message) + coreSetFailed(errorMessage(pError.from, pError)) } } diff --git a/src/tests/FilesHelper.test.ts b/src/tests/FilesHelper.test.ts index 3f709d9e..269b91ca 100644 --- a/src/tests/FilesHelper.test.ts +++ b/src/tests/FilesHelper.test.ts @@ -1,45 +1,135 @@ -/* eslint global-require: 0, @typescript-eslint/no-var-requires: 0 */ -import {Env, p} from './mocks/env' -import { debug as coreDebug } from '@actions/core' -let env:Env // env object +import {Env, p, getTestFiles, getTestEvents} from './mocks/env' -beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, 'push') }) -afterEach(() => { - process.env = {...env.envStart} - jest.resetModules() - env = new Env({}, {}, 'push') -}) -it.each(p.getTestEvents(p.getFormatExtInputs, 'push')) -('Sets %s ext for input "%s" should be "%s"', (inputName, input, expected) => { - const ext = require('../FilesHelper').getFormatExt(input) - expect(ext).toBe(expected) -}) -it.each(p.getTestEvents(p.formatChangedFilesInput, 'push')) -('Formats %o', (inputName, input, expected) => { - const ext = require('../FilesHelper').formatChangedFiles(inputName.format, input) - expect(ext).toBe(expected) -}) -it.each([1,2,3,4,5]) -('#%i Correctly sorts GithubFile array into ChangedFiles object', (inputName) => { - console.log(process.env.HOME) - const fileStatus = ['added', 'removed', 'modified'] as string[] - p.normalFileArray[Math.floor(Math.random() * p.normalFileArray.length)] - let githubFiles:any[] = [] - let stats = {files: 0, added: 0, removed: 0, modified: 0} as {[key:string]: number} - p.normalFileArray.forEach(file => { - const fStatus = fileStatus[Math.floor(Math.random() * fileStatus.length)] as string - stats.files++ // increment number of files - stats[fStatus]++ // increment status - githubFiles.push({ - filename: file, - status: fStatus}) - }) - const ext = require('../FilesHelper').sortChangedFiles(githubFiles) - const coreDebug = require('@actions/core').debug - expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining(JSON.stringify(githubFiles, null, 2))) - let retStats = {files: 0, added: 0, removed: 0, modified: 0} as {[key:string]: number} - Object.keys(ext).forEach(key => { - retStats[key] = ext[key].length // add status total +let env:Env + +describe('Testing FilesHelper.ts...', () => { + describe('...with push event...', () => { + beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, 'push') }) + afterEach(() => { + process.env = {...env.envStart} + jest.resetModules() + env = new Env({}, {}, 'push') + }) + /** + * @function sortChangedFiles + */ + describe('...with function sortChangedFiles...', () => { + it.each([1,2,3,4,5,6,7,8,9,10]) + ('...correctly sorts GithubFile array into ChangedFiles object %i/10 times', () => { + const { files, stats } = getTestFiles() + const changedFiles = require('../FilesHelper').sortChangedFiles(files) + const coreDebug = require('@actions/core').debug + expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining(JSON.stringify(files, null, 2))) + const retStats = {files: 0, added: 0, removed: 0, modified: 0} as {[key:string]: number} + Object.keys(changedFiles).forEach(key => { + retStats[key] = changedFiles[key].length + }) + expect(retStats).toStrictEqual(stats) + }) + it.each([1,2,3,4,5,6,7,8,9,10]) + ('...correctly sorts GithubFile array into ChangedFiles object without filenames %i/10 times', () => { + const { files, stats } = getTestFiles() + const changedFiles = require('../FilesHelper').sortChangedFiles(files) + const coreDebug = require('@actions/core').debug + expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining(JSON.stringify(files, null, 2))) + const retStats = {files: 0, added: 0, removed: 0, modified: 0} as {[key:string]: number} + Object.keys(changedFiles).forEach(key => { + retStats[key] = changedFiles[key].length + }) + expect(retStats).toStrictEqual(stats) + }) + it('...throws an error', () => { + expect(() => + require('../FilesHelper').sortChangedFiles({filename: '/test/file.txt', status: 'noexist'})).toThrowError(JSON.stringify({ + error: '500/TypeError', + from: 'sortChangedFiles', + message: 'There was an issue sorting files changed.', + payload: JSON.stringify({})}, null, 2)) + }) + }) + /** + * @function getFormatExt + */ + describe('...with function getFormatExt...', () => { + it.each(getTestEvents(p.getFormatExtInputs, 'push')) + ('...sets %s ext for input "%s" should be "%s"', (inputName, input, expected) => { + const ext = require('../FilesHelper').getFormatExt(input) + expect(ext).toBe(expected) + }) + }) + /** + * @function formatChangedFiles + */ + describe('...with function formatChangedFiles...', () => { + it.each(getTestEvents(p.changedFilesInput('push'), 'push')) + ('...formats %o', (inputName, input, expected) => { + const ext = require('../FilesHelper').formatChangedFiles(inputName.format, input) + expect(ext).toBe(expected) + }) + }) + /** + * @function writeFiles + */ + describe('...with function writeFiles...', () => { + it.each(getTestEvents(p.changedFilesInput('push'), 'push')) + ('...writesFiles %o', (inputName, input, expected) => { + const coreDebug = require('@actions/core').debug + const fsWriteFilesSync = require('fs').writeFileSync + const format = require('../FilesHelper').getFormatExt(inputName.format) + require('../FilesHelper').writeFiles(inputName.format, 'testKey', input) + expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining(JSON.stringify(input, null, 2))) + expect(fsWriteFilesSync).toHaveBeenCalledWith(`${process.env.HOME}/files_testKey${format}`, expected, 'utf-8') + }) + it.each(getTestEvents(p.changedFilesInput('push'), 'push')) + ('...writesFiles %o with files key', (inputName, input, expected) => { + const coreDebug = require('@actions/core').debug + const fsWriteFilesSync = require('fs').writeFileSync + const format = require('../FilesHelper').getFormatExt(inputName.format) + require('../FilesHelper').writeFiles(inputName.format, 'files', input) + expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining(JSON.stringify(input, null, 2))) + expect(fsWriteFilesSync).toHaveBeenCalledWith(`${process.env.HOME}/files${format}`, expected, 'utf-8') + }) + it('...throws error', () => { + const coreDebug = require('@actions/core').debug + expect(() => + require('../FilesHelper').writeFiles('error', 'testKey', 'json')).toThrowError(new Error(JSON.stringify({ + error: '500/TypeError', + from: 'writeFiles', + message: 'There was an issue writing output files.', + payload: JSON.stringify({})}, null, 2))) + expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining('Writing output file /Users/bkillian/files_testKey.txt.txt with error and files "json"')) + }) + }) + /** + * @function writeOutput + */ + describe('...with function writeOutput...', () => { + it.each(getTestEvents(p.changedFilesInput('push'), 'push')) + ('...writeOutput %o', (inputName, input, expected) => { + const coreDebug = require('@actions/core').debug + const coreSetOutput = require('@actions/core').setOutput + require('../FilesHelper').writeOutput(inputName.format, 'testKey', input) + expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining(JSON.stringify(input, null, 2))) + expect(coreSetOutput).toHaveBeenCalledWith(`files_testKey`, expected) + }) + it.each(getTestEvents(p.changedFilesInput('push'), 'push')) + ('...writeOutput %o with files key', (inputName, input, expected) => { + const coreDebug = require('@actions/core').debug + const coreSetOutput = require('@actions/core').setOutput + require('../FilesHelper').writeOutput(inputName.format, 'files', input) + expect(coreDebug).toHaveBeenCalledWith(expect.stringContaining(JSON.stringify(input, null, 2))) + expect(coreSetOutput).toHaveBeenCalledWith(`files`, expected) + }) + it('...throws error', () => { + const coreDebug = require('@actions/core').debug + expect(() => + require('../FilesHelper').writeOutput('error', 'testKey', 'json')).toThrowError(new Error(JSON.stringify({ + error: '500/TypeError', + from: 'writeOutput', + message: 'There was an issue setting action outputs.', + payload: JSON.stringify({})}, null, 2))) + expect(coreDebug).toHaveBeenCalledWith('Writing output files_testKey with error and files "json"') + }) + }) }) - expect(retStats).toStrictEqual(stats) }) \ No newline at end of file diff --git a/src/tests/GithubHelper.test.ts b/src/tests/GithubHelper.test.ts index 7e1609ab..cfbb39e3 100644 --- a/src/tests/GithubHelper.test.ts +++ b/src/tests/GithubHelper.test.ts @@ -1,44 +1,110 @@ -/* eslint global-require: 0, @typescript-eslint/no-var-requires: 0 */ -import {Env, p} from './mocks/env' +import {Env, p, getTestEvents} from './mocks/env' -let env:Env // env object +let env:Env -describe.each(p.testEvents)('Testing %s event...', event => { - beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, event) }) - afterEach(() => { - process.env = {...env.envStart} - jest.resetModules() - env = new Env({}, {}, event) - }) - describe('...with function initClientTests...', () => { - it.each(p.getTestEvents(p.initClientTestInputs, event)) - ('%s', (title, input, expected) => { - const gh = require('../GithubHelper').initClient(input) - const {GitHub} = require('@actions/github') - expect(GitHub).toHaveBeenCalledTimes(1) - expect(GitHub).toHaveBeenCalledWith(expected) - expect(gh).toEqual(env.octokitMock) +describe('Testing GithubHelper.ts...', () => { + describe.each(p.testEvents)('...with %s event...', event => { + beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, event) }) + afterEach(() => { + process.env = {...env.envStart} + jest.resetModules() + env = new Env({}, {}, event) }) - }) - describe.each([['getChangedPRFiles', p.getChangedPRFilesTestInputs], ['getChangedPushFiles', p.getChangedPushFilesTestInputs], ['getChangedFiles', p.getChangedFilesTestInputs]]) - ('...with function %s...', (method, inputs) => { - it.each(p.getTestEvents(inputs, event)) - ('...it %s', async (title, input, expected) => { - if (title.includes('throws an error')) { - expect.assertions(1); - if (method === 'getChangedPRFiles') await expect(require("../GithubHelper") - .getChangedPRFiles(env.githubMock, input.repo, input.owner, input.pullNumber)).rejects.toThrowError(Error) - else if (method === 'getChangedPushFiles') await expect(require("../GithubHelper").getChangedPushFiles(env.githubMock, input.repo, input.owner, input.before, input.after)).rejects.toThrow(Error) - else if (method === 'getChangedFiles') await expect(require("../GithubHelper") - .getChangedFiles(env.githubMock, input.repo, { ...input })).rejects.toThrowError(Error) - } else { - let files: any[] = [] - if (method === 'getChangedPRFiles') files = await require("../GithubHelper").getChangedPRFiles(env.githubMock, input.repo, input.owner, input.pullNumber) - else if (method === 'getChangedPushFiles') files = await require("../GithubHelper").getChangedPushFiles(env.githubMock, input.repo, input.owner, input.before, input.after) - else if (method === 'getChangedFiles') files = await require("../GithubHelper").getChangedFiles(env.githubMock, input.repo, { ...input }) - expect(files).toStrictEqual(expected) - expect(files.length).toBe(7) - } + /** + * @function initClient + */ + describe('...with function initClientTests...', () => { + it.each(getTestEvents(p.initClientTestInputs, event)) + ('...%s', async (title, input, expected) => { + process.env = {...env.envStart} + env = new Env({}, {}, event) + let gh + if (title.includes('without a token')) expect(() => + require('../GithubHelper').initClient(input) + ).toThrowError(new Error(JSON.stringify({error: '500/Error', from: 'initClient', message: 'There was an error creating github client. Please check your token.', payload: {}}, null, 2))) + else { + gh = require('../GithubHelper').initClient(input) + const {GitHub} = require('@actions/github') + expect(GitHub).toHaveBeenCalledTimes(1) + expect(GitHub).toHaveBeenCalledWith(expected) + expect(gh).toEqual(env.octokitMock) + } + }) + }) + /** + * @function getChangedPRFiles + */ + describe('...with function getChangedPRFiles...', () => { + it.each(getTestEvents(p.getChangedPRFilesTestInputs, event)) + ('...%s', async (title, input, expected) => { + if (title.includes('throws an error')) { + expect.assertions(1) + await expect(require("../GithubHelper").getChangedPRFiles(env.octokitMock, input.repo, input.owner, input.pullNumber)).rejects.toThrowError(new Error(JSON.stringify(expected,null,2))) + } else { + let files: any[] = [] + files = await require("../GithubHelper").getChangedPRFiles(env.octokitMock, input.repo, input.owner, input.pullNumber) + expect(files).toStrictEqual(expected) + expect(files.length).toBe(7) + } + }) + it('...throws errows', async () => { + await expect(require('../GithubHelper').getChangedPRFiles(env.octokitMock, 'trilom/file-changes-action', 'error','error',)).rejects.toThrowError(new Error(JSON.stringify( + { error: '500/Unknown Error:Error', + from: 'getChangedPRFiles', + message: 'There was an error getting change files for repo:trilom/file-changes-action owner:error pr:error', + payload:JSON.stringify({ name: 'HttpError', status: '500' })}, null, 2))) + await expect(require('../GithubHelper').getChangedPRFiles(env.octokitMock, 'trilom/file-changes-action', 'unknown','unknown',)).rejects.toThrowError(new Error(JSON.stringify( + { error: '500/Unknown Error:', + from: 'getChangedPRFiles', + message: 'There was an error getting change files for repo:trilom/file-changes-action owner:unknown pr:unknown', + payload: ''}, null, 2))) + }) + }) + /** + * @function getChangedPushFiles + */ + describe('...with function getChangedPushFiles...', () => { + it.each(getTestEvents(p.getChangedPushFilesTestInputs, event)) + ('...%s', async (title, input, expected) => { + if (title.includes('throws an error')) { + expect.assertions(1) + await expect(require("../GithubHelper").getChangedPushFiles(env.octokitMock, input.repo, input.owner, input.before, input.after)).rejects.toThrowError(new Error(JSON.stringify(expected,null,2))) + } else { + let files: any[] = [] + files = await require("../GithubHelper").getChangedPushFiles(env.octokitMock, input.repo, input.owner, input.before, input.after) + expect(files).toStrictEqual(expected) + expect(files.length).toBe(7) + } + }) + it('...throws errows', async () => { + await expect(require('../GithubHelper').getChangedPushFiles(env.octokitMock, 'trilom/file-changes-action', 'error','error','error')).rejects.toThrowError(new Error(JSON.stringify( + { error: '500/Unknown Error:Error', + from: 'getChangedPushFiles', + message: 'There was an error getting change files for repo:trilom/file-changes-action owner:error base:error head:error', + payload:JSON.stringify({ name: 'HttpError', status: '500' })}, null, 2))) + await expect(require('../GithubHelper').getChangedPushFiles(env.octokitMock, 'trilom/file-changes-action', 'unknown','unknown','unknown')).rejects.toThrowError(new Error(JSON.stringify( + { error: '500/Unknown Error:', + from: 'getChangedPushFiles', + message: 'There was an error getting change files for repo:trilom/file-changes-action owner:unknown base:unknown head:unknown', + payload: ''}, null, 2))) + }) + }) + /** + * @function getChangedFiles + */ + describe('...with function getChangedFiles...', () => { + it.each(getTestEvents(p.getChangedFilesTestInputs, event)) + ('...%s', async (title, input, expected) => { + if (title.includes('throws an error')) { + expect.assertions(1) + await expect(require("../GithubHelper").getChangedFiles(env.octokitMock, input.repo, { ...input })).rejects.toThrowError(new Error(JSON.stringify(expected,null,2))) + } else { + let files: any[] = [] + files = await require("../GithubHelper").getChangedFiles(env.octokitMock, input.repo, { ...input }) + expect(files).toStrictEqual(expected) + expect(files.length).toBe(7) + } + }) }) }) }) \ No newline at end of file diff --git a/src/tests/InputHelper.test.ts b/src/tests/InputHelper.test.ts index 9fff63c8..ce947019 100644 --- a/src/tests/InputHelper.test.ts +++ b/src/tests/InputHelper.test.ts @@ -1,135 +1,152 @@ -/* eslint global-require: 0, @typescript-eslint/no-var-requires: 0 */ -import {Env, p, eventName} from './mocks/env' +import {Env, p, eventName, getTestEvents} from './mocks/env' -let env: Env // env object +let env: Env -describe.each(p.testEvents)('Testing %s event...', event => { - beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, event)}) - afterEach(() => { - process.env = {...env.envStart} - jest.resetModules() - env = new Env({}, {}, event) +describe('Testing InputHelper.ts...', () => { + describe.each(p.testEvents)('...with %s event...', event => { + beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, event)}) + afterEach(() => { + process.env = {...env.envStart} + jest.resetModules() + env = new Env({}, {}, event) + }) + /** + * @function getInputs + */ + describe('...with function getInputs...', () => { + it('...sets correct default input parameters.', () => { + const {payload, issue, eventName:contextEventName} = env.context + const { prNumber, pushAfter, pushBefore, githubToken, githubRepo, output, fileOutput, event:inputEventName } = require('../InputHelper').getInputs() + const {getInput} = require('@actions/core') + if (event.includes('push')) { + expect(prNumber).toBe(NaN) + expect(pushAfter).toBe(payload.after) + expect(pushBefore).toBe(payload.before) + } + if (event.includes('pull_request') || event.includes('issue_comment')) { + expect(prNumber).toBe(issue.number) + if (event === 'pull_request_synchronize') { + expect(pushAfter).toBe(payload.after) + expect(pushBefore).toBe(payload.before) + } else { + expect(pushAfter).toBeFalsy() + expect(pushBefore).toBeFalsy() + } + } + expect(githubToken).toBe(process.env.INPUT_GITHUBTOKEN) + expect(githubRepo).toBe(process.env.GITHUB_REPOSITORY) + expect(output).toBe('json') + expect(fileOutput).toBe('json') + expect(inputEventName).toBe(contextEventName) + expect(getInput).toHaveBeenCalledTimes(7) + }) + it('...throws error with no token (undefined) process.env["GITHUB_TOKEN"] or (undefined) input githubToken', () => { + delete process.env.GITHUB_TOKEN + delete process.env.INPUT_GITHUBTOKEN + const {getInput} = require('@actions/core') + expect(() => { + require('../InputHelper').getInputs() + }).toThrowError(new Error(JSON.stringify({ + error: '500/getInputs Error', + from: 'getInputs', + message: 'Received an issue getting action inputs.', + payload: JSON.parse(JSON.stringify({ + GITHUB_WORKSPACE:"/Users/bkillian/repos/file-changes-action/src/tests/workspace/github", + GITHUB_REPOSITORY:"trilom-test/file-changes-action", + GITHUB_ACTION:"file-changes-action", + GITHUB_EVENT_PATH:`/Users/bkillian/repos/file-changes-action/tests/events/${event}.json`, + GITHUB_EVENT_NAME:eventName(event)}, null, 2)) + }, null, 2))) + expect(getInput).toHaveBeenCalledTimes(1) + }) + it('...throws error with empty string ("") process.env["GITHUB_TOKEN"] or empty string ("") input githubToken', () => { + env.updateInput({ githubToken: '' }) + process.env.GITHUB_TOKEN = '' + const {getInput} = require('@actions/core') + expect(() => { + require('../InputHelper').getInputs() + }).toThrowError(new Error(JSON.stringify({ + error: '500/getInputs Error', + from: 'getInputs', + message: 'Received an issue getting action inputs.', + payload: JSON.parse(JSON.stringify({ + GITHUB_TOKEN:"", + GITHUB_WORKSPACE:"/Users/bkillian/repos/file-changes-action/src/tests/workspace/github", + GITHUB_REPOSITORY:"trilom-test/file-changes-action", + GITHUB_ACTION:"file-changes-action", + GITHUB_EVENT_PATH:`/Users/bkillian/repos/file-changes-action/tests/events/${event}.json`, + GITHUB_EVENT_NAME:eventName(event), + INPUT_GITHUBTOKEN:""}, null, 2)) + }, null, 2))) + expect(getInput).toHaveBeenCalledTimes(1) + }) + it.each(getTestEvents(p.inputTestInputs, event)) + ('...sets %s input "%s" should be %p', (inputName, input, expected) => { + env.updateInput({[inputName]: input}) + const {payload, issue, eventName:contextEventName } = env.context + const { prNumber, pushAfter, pushBefore, githubToken, githubRepo, output, fileOutput, event:inputEventName } = require('../InputHelper').getInputs() + const {getInput} = require('@actions/core') + if (event.includes('push')) { + expect(prNumber).toBe((inputName === 'prNumber') ? expected : NaN) + expect(pushAfter).toBe((inputName === 'pushAfter') ? expected : payload.after ) + expect(pushBefore).toBe((inputName === 'pushBefore') ? expected : payload.before) + } + if (event.includes('pull_request') || event.includes('issue_comment')) { + expect(prNumber).toBe((inputName === 'prNumber') ? expected : issue.number) + if (event === 'pull_request_synchronize') { + expect(pushAfter).toBe((inputName === 'pushAfter') ? expected : payload.after ) + expect(pushBefore).toBe((inputName === 'pushBefore') ? expected : payload.before) + } else { + expect(pushAfter).toBe((inputName === 'pushAfter') ? expected : false ) + expect(pushBefore).toBe((inputName === 'pushBefore') ? expected : false ) + } + } + expect(githubToken).toBe((inputName === 'githubToken') ? expected : 'EnvDefaultToken') + expect(githubRepo).toBe((inputName === 'githubRepo') ? expected : process.env.GITHUB_REPOSITORY) + expect(output).toBe((inputName === 'output') ? expected : 'json') + expect(fileOutput).toBe((inputName === 'fileOutput') ? expected : 'json') + expect(inputEventName).toBe(contextEventName) + expect(getInput).toHaveBeenCalledTimes(7) + }) + }) + /** + * @function inferInput + */ + describe('...with function inferInput...', () => { + it.each(getTestEvents(p.inferTestInputs, event)) + ('...%s', (title, input, expected) => { + const {error} = require('@actions/core') + const {warning} = require('@actions/core') + if (title.includes('ERROR with no')) { + expect(() => { + require('../InputHelper').inferInput(input.before, input.after, input.pr) + }).toThrowError(new Error(JSON.stringify({ + error: '500/inferInput Error', + from: 'inferInput', + message: `Received event from ${eventName(event)}, but received no inputs. {event_name:${eventName(event)}, pr: NaN, before:, after:}`, + payload: "" + }, null, 2))) + } else if (title.includes('ERROR with single')) { + expect(() => { + require('../InputHelper').inferInput(input.before, input.after, input.pr) + }).toThrowError(new Error(JSON.stringify({ + error: '500/inferInput Error', + from: 'inferInput', + message: `Received event from ${eventName(event)}, but only received a before(${input.before}) or after(${input.after}).\n I need both of these if you want to use a Push event.`, + payload: "" + }, null, 2))) + } else { + const data = require('../InputHelper').inferInput(input.before, input.after, input.pr) + Object.keys(data).forEach((key) => expect(data[key]).toBe(expected[key])) + expect(error).not.toHaveBeenCalled() + } + if (title.includes('WARN weird')) + expect(warning).toHaveBeenCalledWith(expect.stringContaining(`received a before(${input.before}) or after(${input.after}) value.`)) + if (title.includes('WARN all')) + expect(warning).toHaveBeenCalledWith(expect.stringContaining(`but received a before(${input.before}), after(${input.after}), and PR(${input.pr}).`)) + else + expect(error).not.toHaveBeenCalled() + }) + }) }) - it('Sets correct default input parameters.', () => { - const {payload, issue} = env.contextMock - const { prNumber, pushAfter, pushBefore, githubToken, githubRepo, output, fileOutput } = require('../InputHelper').getInputs() - const {getInput} = require('@actions/core') - // evaluate outputs - if (event.includes('push')) { - expect(prNumber).toBe(NaN) - expect(pushAfter).toBe(payload.after) - expect(pushBefore).toBe(payload.before) - } - if (event.includes('pull_request') || event.includes('issue_comment')) { - expect(prNumber).toBe(issue.number) - if (event === 'pull_request_synchronize') { - expect(pushAfter).toBe(payload.after) - expect(pushBefore).toBe(payload.before) - } else { - expect(pushAfter).toBeFalsy() - expect(pushBefore).toBeFalsy() - } - } - expect(githubToken).toBe(process.env.INPUT_GITHUBTOKEN) - expect(githubRepo).toBe(process.env.GITHUB_REPOSITORY) - expect(output).toBe('json') - expect(fileOutput).toBe('json') - expect(getInput).toHaveBeenCalledTimes(7) - }) - it('Throws error with no token (undefined) process.env["GITHUB_TOKEN"] or (undefined) input githubToken', () => { - delete process.env.GITHUB_TOKEN - delete process.env.INPUT_GITHUBTOKEN - const {getInput} = require('@actions/core') - expect(() => { - require('../InputHelper').getInputs() - }).toThrowError(new Error(JSON.stringify({ - error: '500/getInputs Error', - from: 'getInputs', - message: 'Received an issue getting action inputs.', - payload: JSON.parse(JSON.stringify({ - GITHUB_WORKSPACE:"/Users/bkillian/repos/file-changes-action/src/tests/workspace/github", - GITHUB_REPOSITORY:"trilom-test/file-changes-action", - GITHUB_ACTION:"file-changes-action", - GITHUB_EVENT_PATH:`/Users/bkillian/repos/file-changes-action/tests/events/${event}.json`, - GITHUB_EVENT_NAME:eventName(event)}, null, 2)) - }, null, 2))) - expect(getInput).toHaveBeenCalledTimes(1) - }) - it('Throws error with empty string ("") process.env["GITHUB_TOKEN"] or empty string ("") input githubToken', () => { - env.updateInput({ githubToken: '' }) - process.env.GITHUB_TOKEN = '' - const {getInput} = require('@actions/core') - expect(() => { - require('../InputHelper').getInputs() - }).toThrowError(new Error(JSON.stringify({ - error: '500/getInputs Error', - from: 'getInputs', - message: 'Received an issue getting action inputs.', - payload: JSON.parse(JSON.stringify({ - GITHUB_TOKEN:"", - GITHUB_WORKSPACE:"/Users/bkillian/repos/file-changes-action/src/tests/workspace/github", - GITHUB_REPOSITORY:"trilom-test/file-changes-action", - GITHUB_ACTION:"file-changes-action", - GITHUB_EVENT_PATH:`/Users/bkillian/repos/file-changes-action/tests/events/${event}.json`, - GITHUB_EVENT_NAME:eventName(event), - INPUT_GITHUBTOKEN:""}, null, 2)) - }, null, 2))) - expect(getInput).toHaveBeenCalledTimes(1) - }) - // test getInputs function - it.each(p.getTestEvents(p.inputTestInputs, event)) - ('Sets %s input "%s" should be %p', (inputName, input, expected) => { - env.updateInput({[inputName]: input}) - const {payload, issue} = env.contextMock - const { prNumber, pushAfter, pushBefore, githubToken, githubRepo, output, fileOutput } = require('../InputHelper').getInputs() - const {getInput} = require('@actions/core') - // evaluate outputs - if (event.includes('push')) { - expect(prNumber).toBe((inputName === 'prNumber') ? expected : NaN) - expect(pushAfter).toBe((inputName === 'pushAfter') ? expected : payload.after ) - expect(pushBefore).toBe((inputName === 'pushBefore') ? expected : payload.before) - } - if (event.includes('pull_request') || event.includes('issue_comment')) { - expect(prNumber).toBe((inputName === 'prNumber') ? expected : issue.number) - if (event === 'pull_request_synchronize') { - expect(pushAfter).toBe((inputName === 'pushAfter') ? expected : payload.after ) - expect(pushBefore).toBe((inputName === 'pushBefore') ? expected : payload.before) - } else { - expect(pushAfter).toBe((inputName === 'pushAfter') ? expected : false ) - expect(pushBefore).toBe((inputName === 'pushBefore') ? expected : false ) - } - } - expect(githubToken).toBe((inputName === 'githubToken') ? expected : 'EnvDefaultToken') - expect(githubRepo).toBe((inputName === 'githubRepo') ? expected : process.env.GITHUB_REPOSITORY) - expect(output).toBe((inputName === 'output') ? expected : 'json') - expect(fileOutput).toBe((inputName === 'fileOutput') ? expected : 'json') - expect(getInput).toHaveBeenCalledTimes(7) - }) - // test inferInput function - it.each(p.getTestEvents(p.inferTestInputs, event)) - ('%s', (title, input, expected) => { - const {error} = require('@actions/core') - const {warning} = require('@actions/core') - if (title.includes('ERROR')) { - expect(() => { - require('../InputHelper').inferInput(input.before, input.after, input.pr) - }).toThrowError(new Error(JSON.stringify({ - error: '500/inferInput Error', - from: 'inferInput', - message: `Received event from ${eventName(event)}, but received no inputs. {event_name:${eventName(event)}, pr: NaN, before:, after:}`, - payload: "" - }, null, 2))) - } else { - const data = require('../InputHelper').inferInput(input.before, input.after, input.pr) - Object.keys(data).forEach((key) => expect(data[key]).toBe(expected[key])) - expect(error).not.toHaveBeenCalled() - } - // evaluate outputs - if (title.includes('WARN weird')) - expect(warning).toHaveBeenCalledWith(expect.stringContaining(`received a before(${input.before}) or after(${input.after}) value.`)) - if (title.includes('WARN all')) - expect(warning).toHaveBeenCalledWith(expect.stringContaining(`but received a before(${input.before}), after(${input.after}), and PR(${input.pr}).`)) - else - expect(error).not.toHaveBeenCalled() - }) -}) +}) \ No newline at end of file diff --git a/src/tests/UtilsHelper.test.ts b/src/tests/UtilsHelper.test.ts index c9134007..e5257a83 100644 --- a/src/tests/UtilsHelper.test.ts +++ b/src/tests/UtilsHelper.test.ts @@ -1,15 +1,47 @@ -/* eslint global-require: 0, @typescript-eslint/no-var-requires: 0 */ -import {Env, p} from './mocks/env' -let env: Env // env object - -beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, 'push')}) -afterEach(() => { - process.env = {...env.envStart} - jest.resetModules() - env = new Env({}, {}, 'push') +import {Env, p, getTestEvents} from './mocks/env' + +let env: Env +describe('Testing UtilsHelper.ts...', () => { + describe('...with push event...', () => { + beforeAll(() => { env = new Env({}, {githubToken: 'TestToken'}, 'push')}) + afterEach(() => { + process.env = {...env.envStart} + jest.resetModules() + env = new Env({}, {}, 'push') + }) + /** + * @function getErrorString + */ + describe('...with function getErrorString...', () => { + it('...can throw an error', () => { + const error = require('../UtilsHelper').getErrorString() + expect(JSON.stringify(JSON.parse(error))).toBe(JSON.stringify({error:'500/undefined', payload:''})) + }) + + it('...can throw an error for my error', () => { + const {setFailed, error:coreError} = require('@actions/core') + const obj = {a: {}} + obj.a = {b:obj} + expect(() => + require('../UtilsHelper').getErrorString('test', 200, 'test', 'test', obj) + ).toThrowError(JSON.stringify({name: '500/undefined', message: 'Error throwing error.'})) + // expect(JSON.stringify(JSON.parse(error))).toBe(JSON.stringify({error:'500/undefined', payload:''})) + expect(setFailed).toBeCalledWith(expect.stringContaining('Error throwing error.')) + expect(coreError).toBeCalledWith(expect.stringContaining('Error throwing error.')) + }) + }) + /** + * @function errorMessage + */ + describe('...with function errorMessage...', () => { + it.each(getTestEvents(p.errorMessageInputs, 'push'))('...for function %s', (f, e, expected) => { + const error = require('../UtilsHelper').errorMessage(f, e) + expect(error).toBe(`${expected}\nException: ${JSON.stringify(e, null, 2)}`) + }) + }) + }) }) -it('Make sure that I can throw an error', () => { - let error = require('../UtilsHelper').getErrorString() - expect(JSON.stringify(JSON.parse(error))).toBe(JSON.stringify({error:'500/undefined', payload:''})) -}) \ No newline at end of file + + + diff --git a/src/tests/main.test.ts b/src/tests/main.test.ts index 6c4ca9b2..36beea94 100644 --- a/src/tests/main.test.ts +++ b/src/tests/main.test.ts @@ -1,4 +1,51 @@ +import {Env, p, getTestEvents, getTestFiles} from './mocks/env' -it('test', () => { - expect(true).toBeTruthy() +let env: Env = new Env({}, {}) + +describe('Testing main.ts...', () => { + describe.each(p.testEvents)('...with %s event...', event => { + /** + * @function run + */ + describe('...with function run...', () => { + describe.each(getTestEvents(p.getFormatExtInputs, 'push'))('...with fileOutput %s...', (fileOutputName, fileOutputInput, outputExpected) => { + describe.each(getTestEvents(p.changedFilesInput(event),event))('...with output %o...', (outputInput, outputFiles, expectedOutput) => { + afterEach(() => { + process.env = {...env.envStart} + jest.resetAllMocks() + jest.resetModules() + env = new Env({}, { + githubRepo: 'file-changes-action', + githubToken: 'TestToken', + output: outputInput.format, + fileOutput: fileOutputInput, + }) + }) + it('...normal', async () => { + const githubHelper = require('../GithubHelper') + const filesHelper = require('../FilesHelper') + githubHelper.getChangedFiles = jest.fn(() => getTestFiles(outputFiles).files) + filesHelper.writeOutput = jest.fn(() => {}) + filesHelper.writeFiles = jest.fn(() => {}) + const processExitMock = jest.spyOn(process, 'exit').mockImplementation((code?:number | undefined) => code as never) + const {run} = require('../main') + await run + expect(githubHelper.getChangedFiles).toBeCalled() + expect(filesHelper.writeOutput).toBeCalled() + expect(filesHelper.writeFiles).toBeCalled() + expect(processExitMock).toBeCalled() + }) + it.each(getTestEvents(p.mainErrorInputs, 'push'))('...throws error for function %s...', async (f, e, expected) => { + const inputHelper = require('../InputHelper') + const {setFailed} = require('@actions/core') + inputHelper.getInputs = jest.fn(() => {throw new Error(e)}) + const {run} = require('../main') + await expect(run).toBe(run) + expect(setFailed).toBeCalledWith(`${expected}\nException: ${e}`) + expect(inputHelper.getInputs).toHaveBeenCalledTimes(1) + }) + }) + }) + }) + }) }) \ No newline at end of file diff --git a/src/tests/mocks/core/index.test.ts b/src/tests/mocks/core/index.test.ts new file mode 100644 index 00000000..68b28c60 --- /dev/null +++ b/src/tests/mocks/core/index.test.ts @@ -0,0 +1,54 @@ +import {mock} from '.' + +const core = mock() + +describe('Testing CoreMock object...', () => { + beforeAll(() => jest.restoreAllMocks()) + it('...CoreMock is a mock', () => { + expect(jest.isMockFunction(core.getInput)).toBe(true) + expect(jest.isMockFunction(core.setFailed)).toBe(true) + expect(jest.isMockFunction(core.setOutput)).toBe(true) + expect(jest.isMockFunction(core.debug)).toBe(true) + expect(jest.isMockFunction(core.warning)).toBe(true) + expect(jest.isMockFunction(core.info)).toBe(true) + expect(jest.isMockFunction(core.error)).toBe(true) + }) + it('...CoreMock mocks core', () => { + const realCore = require('@actions/core') + expect(core).toMatchObject(realCore) + }) + it('...CoreMock mocks setFailed', () => { + core.setFailed('Test Message') + expect(core.error).toBeCalledWith('Test Message') + expect(core.setFailed).toBeCalledWith('Test Message') + }) + it('...CoreMock mocks setOutput', () => { + core.setOutput('TestName', 'TestValue') + expect(core.setOutput).toBeCalledWith('TestName', 'TestValue') + }) + it('...CoreMock mocks setOutput error', () => { + expect(() => + core.setOutput('ERROROUTPUT', 'TestValue')).toThrowError(new Error(JSON.stringify({ name: 'CoreError', status: '500' }))) + }) + it('...CoreMock mocks getInput', () => { + process.env.INPUT_TEST = 'TESTINPUT' + const input = core.getInput('TEST') + expect(input).toBe('TESTINPUT') + }) + it('...CoreMock mocks debug', () => { + core.debug('Test Message') + expect(core.debug).toBeCalledWith('Test Message') + }) + it('...CoreMock mocks warning', () => { + core.warning('Test Message') + expect(core.warning).toBeCalledWith('Test Message') + }) + it('...CoreMock mocks info', () => { + core.info('Test Message') + expect(core.info).toBeCalledWith('Test Message') + }) + it('...CoreMock mocks error', () => { + core.error('Test Message') + expect(core.error).toBeCalledWith('Test Message') + }) +}) \ No newline at end of file diff --git a/src/tests/mocks/core/index.ts b/src/tests/mocks/core/index.ts new file mode 100644 index 00000000..47194927 --- /dev/null +++ b/src/tests/mocks/core/index.ts @@ -0,0 +1,33 @@ +import type { CoreMock } from 'typings/CoreMock' + +const coreMock: CoreMock = { + setFailed: jest.fn((message) => { + coreMock.error(message) + // console.error(`setFailed triggered`) + }), + setOutput: jest.fn((name, value) => { + if (name === 'ERROROUTPUT') throw new Error(JSON.stringify({ name: 'CoreError', status: '500' })) + // console.log(`setOutputName: ${name} value: ${value}`) + }), + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getInput: jest.fn((name, options) => { + return process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] + }), + debug: jest.fn((message) => { + // console.debug(`core.debug triggered: ${message}`) + }), + warning: jest.fn((message) => { + // console.warn(`core.warning triggered: ${message}`) + }), + info: jest.fn((message) => { + // console.info(`core.info triggered: ${message}`) + }), + error: jest.fn((message) => { + // console.error(`core.error triggered: ${message}`) + }), +} + +export function mock():CoreMock { + jest.mock('@actions/core', () => coreMock) + return coreMock +} \ No newline at end of file diff --git a/src/tests/mocks/env/env.test.ts b/src/tests/mocks/env/env.test.ts deleted file mode 100644 index bc232ff5..00000000 --- a/src/tests/mocks/env/env.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint global-require: 0, @typescript-eslint/no-var-requires: 0 */ -import {Env, p} from '.' - -let env: Env // env object - -describe('Testing Env object with pull_request event', () => { - // create a brand new context object for each event test set - beforeAll(() => { env = new Env({}, {}, 'pull_request_synchronize') }) - it('Env mocks Octokit.pulls.listFiles', () => { - const request = p.OctokitPullsListFilesRequest - const response = p.OctokitPullsListFilesResponse - return env.githubMock.pulls.listFiles(request).then(data => { - expect(data.data).toBe(response) - return expect(data.data.length).toBe(7) - }) - }) - it('Env mocks Octokit.pulls.listFiles.endpoint.merge', () => { - const request = p.OctokitPullsListFilesEndpointMergeRequest - const response = p.OctokitPullsListFilesEndpointMergeResponse - const data = env.githubMock.pulls.listFiles.endpoint.merge(request) - expect(data).toStrictEqual(response) - }) - it('Env mocks Octokit.repos.paginate for pr', () => { - const request = p.OctokitPaginatePrRequest - const response = p.OctokitPaginatePrResponse - return env.githubMock.paginate(request).then(data => { - expect(data).toStrictEqual(response) - return expect(data.length).toBe(7) - }) - }) - it('Env mocks Octokit.repos.paginate for pr with custom callback', async () => { - const request = p.OctokitPaginatePrRequest - const response = p.OctokitPaginatePrResponse - return env.githubMock.paginate(request, res => { - return res.data - }).then(data => { - expect(data).toStrictEqual(response) - return expect(data.length).toBe(7) - }) - }) -}) - -describe('Testing Env object with push event', () => { - // create a brand new context object for each event test set - beforeAll(() => { - env = new Env({}, {}, 'push') - }) - it('Env mocks Octokit.repos.compareCommits', () => { - const request = p.OctokitReposCompareCommitsRequest - const response = p.OctokitReposCompareCommitsResponse - return env.githubMock.repos.compareCommits(request).then(data => { - expect(data.data.files).toBe(response) - return expect(data.data.files.length).toBe(7) - }) - }) - it('Env mocks Octokit.repos.compareCommits.endpoint.merge', () => { - const request = p.OctokitReposCompareCommitsEndpointMergeRequest - const response = p.OctokitReposCompareCommitsEndpointMergeResponse - const data = env.githubMock.repos.compareCommits.endpoint.merge(request) - expect(data).toStrictEqual(response) - }) - it('Env mocks Octokit.repos.paginate for push', async () => { - const request = p.OctokitPaginatePushRequest - const response = p.OctokitPaginatePushResponse - expect.assertions(1) - const files = await env.githubMock.paginate(request).then(data => { - return data.map(commit => commit.files) - }) - expect(files).toStrictEqual([response]) - }) - it('Env mocks Octokit.repos.paginate for push with custom callback', async () => { - const request = p.OctokitPaginatePushRequest - const response = p.OctokitPaginatePushResponse - const files = await env.githubMock.paginate(request, res => { - return res.data.files - }) - expect(files).toStrictEqual(response) - expect(files.length).toBe(7) - }) -}) diff --git a/src/tests/mocks/env/index.test.ts b/src/tests/mocks/env/index.test.ts new file mode 100644 index 00000000..794e49a3 --- /dev/null +++ b/src/tests/mocks/env/index.test.ts @@ -0,0 +1,148 @@ +import {Env, p, eventName, formatInput, getTestEvents, getTestFiles} from '.' + +let env: Env + +describe('Testing Env object with push event...', () => { + it('...Env sets push as default event', () => { + env = new Env({}, {}) + expect(process.env.GITHUB_EVENT_NAME).toBe('push') + }) +}) + +describe.each(p.testEvents) +('Testing Env object with %s event...', (event) => { + beforeAll(() => { env = new Env({}, {}, event) }) + it('...Env can get correct test file inputs', () => { + const { files, stats } = getTestFiles() + const filesCount = Object.values(stats).reduce((prev, curr) => prev + curr)/2 + expect(files.length).toBe(73) + expect(filesCount).toBe(73) + expect(stats.files).toStrictEqual(73) + expect(stats.files).toStrictEqual(filesCount) + }) + it('...Env can get custom files', () => { + const { files, stats } = getTestFiles(['/test/test', '/test1/test1', '/test2/test2', '/test3/test3']) + const filesCount = Object.values(stats).reduce((prev, curr) => prev + curr)/2 + expect(files.length).toBe(4) + expect(filesCount).toBe(4) + expect(stats.files).toStrictEqual(4) + expect(stats.files).toStrictEqual(filesCount) + }) + it('...Env can get custom file properties', () => { + const { files, stats } = getTestFiles(['/test/test', '/test1/test1', '/test2/test2', '/test3/test3'], {files: 0, test: 0, test1: 0, test2: 0, test3:0 }) + const filesCount = Object.values(stats).reduce((prev, curr) => prev + curr)/2 + expect(files.length).toBe(4) + expect(filesCount).toBe(4) + expect(stats.files).toStrictEqual(4) + expect(stats.files).toStrictEqual(filesCount) + }) + it('...Env can get custom files limited', () => { + const { files, stats } = getTestFiles(['/test/test', '/test1/test1', '/test2/test2', '/test3/test3', '/test4/test4', '/test5/test5', '/test6/test6', '/test7/test7'], { files: 0, added: 0, removed: 0, modified: 0 }, 4) + const filesCount = Object.values(stats).reduce((prev, curr) => prev + curr)/2 + expect(files.length).toBe(4) + expect(filesCount).toBe(8) // this is 8 because it doesnt update the stats object + expect(stats.files).toStrictEqual(8) // this is 8 because it doesnt update the stats object + expect(stats.files).toStrictEqual(filesCount) + }) + it('...Env can get correct test event inputs', () => { + const initClientTestInputs = [ + { inputs: ['test include all'], events: 'all' }, + { inputs: ['test exclude string'], events: 'tall' }, + { inputs: ['test include string'], events: event }, + { inputs: ['test include array'], events: [event, 'tall'] }, + { inputs: ['test exclude array'], events: ['handsome', 'dark', 'tall'] } + ] + const result = getTestEvents(initClientTestInputs, event) + expect(result.length).toBe(3) + }) + it('...Env can get correct process.env.GITHUB_EVENT_NAME', () => { + const result = eventName(event) + if (result.includes('push')) expect(result).toBe('push') + else if (result.includes('pull_request')) expect(result).toBe('pull_request') + else if (result.includes('issue_comment')) expect(result).toBe('issue_comment') + else expect(result).toBe(result.trim()) + }) + it('...Env can format strings for action process.env.INPUT_INPUTNAME', () => { + const input = {test: 'value', REALtest: 'realVALUE', [event]: event} + const result = formatInput(input) + expect(result).toStrictEqual({ + INPUT_TEST: 'value', INPUT_REALTEST: 'realVALUE', + [`INPUT_${event.replace(/ /g, '_').toUpperCase()}`]: event}) + }) + it('...Env can updateInput for action in process.env.INPUT_INPUTNAME without a new object', () => { + env = new Env({}, {test_input: 'test_value'}, event) + expect(process.env.INPUT_TEST_INPUT).toEqual('test_value') + env.updateInput({test_input: 'new_value'}) + expect(process.env.INPUT_TEST_INPUT).toEqual('new_value') + delete process.env.INPUT_TEST_INPUT + }) + if (event === 'push') { + it('...Env mocks Octokit.pulls.listFiles', () => { + // console.log(JSON.stringify(env)) + const request = p.OctokitPullsListFilesRequest + const response = p.OctokitPullsListFilesResponse + return env.octokitMock.pulls.listFiles(request).then(data => { + expect(data.data).toBe(response) + return expect(data.data.length).toBe(7) + }) + }) + it('...Env mocks Octokit.pulls.listFiles.endpoint.merge', () => { + const request = p.OctokitPullsListFilesEndpointMergeRequest + const response = p.OctokitPullsListFilesEndpointMergeResponse + const data = env.octokitMock.pulls.listFiles.endpoint.merge(request) + expect(data).toStrictEqual(response) + }) + it('...Env mocks Octokit.repos.paginate for pr', () => { + const request = p.OctokitPaginatePrRequest + const response = p.OctokitPaginatePrResponse + return env.octokitMock.paginate(request).then(data => { + expect(data).toStrictEqual(response) + return expect(data.length).toBe(7) + }) + }) + it('...Env mocks Octokit.repos.paginate for pr with custom callback', async () => { + const request = p.OctokitPaginatePrRequest + const response = p.OctokitPaginatePrResponse + return env.octokitMock.paginate(request, res => { + return res.data + }).then(data => { + expect(data).toStrictEqual(response) + return expect(data.length).toBe(7) + }) + }) + } + if (event === 'pull_request_synchronize') { + it('...Env mocks Octokit.repos.compareCommits', () => { + const request = p.OctokitReposCompareCommitsRequest + const response = p.OctokitReposCompareCommitsResponse + return env.octokitMock.repos.compareCommits(request).then(data => { + expect(data.data.files).toBe(response) + return expect(data.data.files.length).toBe(7) + }) + }) + it('...Env mocks Octokit.repos.compareCommits.endpoint.merge', () => { + const request = p.OctokitReposCompareCommitsEndpointMergeRequest + const response = p.OctokitReposCompareCommitsEndpointMergeResponse + const data = env.octokitMock.repos.compareCommits.endpoint.merge(request) + expect(data).toStrictEqual(response) + }) + it('...Env mocks Octokit.repos.paginate for push', async () => { + const request = p.OctokitPaginatePushRequest + const response = p.OctokitPaginatePushResponse + expect.assertions(1) + const files = await env.octokitMock.paginate(request).then(data => { + return data.map(commit => commit.files) + }) + expect(files).toStrictEqual([response]) + }) + it('...Env mocks Octokit.repos.paginate for push with custom callback', async () => { + const request = p.OctokitPaginatePushRequest + const response = p.OctokitPaginatePushResponse + const files = await env.octokitMock.paginate(request, res => { + return res.data.files + }) + expect(files).toStrictEqual(response) + expect(files.length).toBe(7) + }) + } +}) \ No newline at end of file diff --git a/src/tests/mocks/env/index.ts b/src/tests/mocks/env/index.ts index ecae1033..861edb03 100644 --- a/src/tests/mocks/env/index.ts +++ b/src/tests/mocks/env/index.ts @@ -1,12 +1,15 @@ -// imports -import * as core from '@actions/core' -import { GitHub } from '@actions/github' -import { Context } from '@actions/github/lib/context' +import type { Context } from '@actions/github/lib/context' +import type { CoreMock } from 'typings/CoreMock' +import type { OctokitMock } from 'typings/OctokitMock' +import type { GitHubMock } from 'typings/GitHubMock' +import type { FsMock } from 'typings/FsMock' +import type { GitHubFile } from 'typings/GitHubFile' import { resolve as _resolve } from 'path' -// join all payloads +import { mock as mockCore } from '../core' +import { mock as mockGitHub } from '../github' +import { mock as mockFs } from '../fs' import * as octokitPayloads from '../octokit/payloads' -import * as envPayloads from './payloads' -import { octokitMock } from '../octokit' +import * as envPayloads from '../../payloads' const payloads = {...octokitPayloads, ...envPayloads} // export payloads and class @@ -19,7 +22,37 @@ export function eventName(e:string):string { return e.trim() } -function formatInput(inputs:{[key:string]: string}):{[key:string]: string}{ +export function getTestEvents(inputs: any, event: string): any[][] { + const ret: any[][] = [] + inputs.forEach((test: any) => { + if (typeof test.events === 'string' && test.events === 'all') + ret.push(test.inputs) // add for all events + else if (typeof test.events === 'string' && test.events === event) + ret.push(test.inputs) // add for named event + else if (Array.isArray(test.events) && test.events.includes(event)) + ret.push(test.inputs) // add for named event in list + }) + return ret +} + +export function getTestFiles( + files: string[] = octokitPayloads.normalFileArray, + stats:{files: number, [key:string]:number} = { files: 0, added: 0, removed: 0, modified: 0 }, + limit: number = octokitPayloads.normalFileArray.length +):{ files: GitHubFile[], stats: {[key:string]:number}} { + const s = stats + const statuses = Object.keys(stats).filter(key => key !== 'files') + return { + files: files.map(file => { + const fStatus = statuses[Math.floor(Math.random() * statuses.length)] as string + s.files += 1 + s[fStatus] += 1 + return { [fStatus]: file, status: fStatus } as unknown as GitHubFile + }).filter((file,i) => limit > i) as unknown as GitHubFile[], + stats: s } +} + +export function formatInput(inputs:{[key:string]: string}):{[key:string]: string}{ return Object.fromEntries(Object.entries(inputs).map(input => { const t = [ input[0].replace(input[0], `INPUT_${input[0].replace(/ /g, '_').toUpperCase()}`), @@ -29,16 +62,6 @@ function formatInput(inputs:{[key:string]: string}):{[key:string]: string}{ export class Env { - constructor( - envVars: {[key:string]: string} = {}, // any additional env vars on top of process.env - inputs: {[key:string]: string} = {}, - event = 'push') // any additional inputs - { - // console.log(`I am initing for event ${event}`) - this.setEnv(event, envVars, inputs) // set env vars with event input - this.setMocks() // set mocks - } - public envDefault: {[key:string]: string} = { GITHUB_TOKEN: 'EnvDefaultToken', GITHUB_WORKSPACE: _resolve(__dirname, '../../workspace/github'), @@ -49,25 +72,43 @@ export class Env public envStart: {[key:string]: string | undefined} = {...process.env} // store shallow copy of process.env on init // set mocks - contextMock!: Context - - coreMock!: any + coreMock: CoreMock - githubMock!: GitHub + githubMock: GitHubMock - octokitMock: GitHub = octokitMock as unknown as GitHub + octokitMock: OctokitMock + + fsMock: FsMock + + context: Context event = 'push' + constructor( + envVars: {[key:string]: string}, // any additional env vars on top of process.env + inputs: {[key:string]: string}, + event?: string) // any additional inputs + { + this.setEnv(event || this.event, envVars, inputs); // set env vars with event input + this.coreMock = mockCore() // mock core + ;({ + github: this.githubMock, + octokit: this.octokitMock, + context: this.context + } = mockGitHub()) // mock github + this.fsMock = mockFs() // mock fs + } + setEnv( - event: string = this.event, + event: string, envVars: {[key:string]: string}, inputs: {[key:string]: string}):void { this.event = event - const eventPayload = _resolve(__dirname, `../../../../tests/events/${this.event}.json`) + const eventPayload = _resolve(__dirname, + `../../../../tests/events/${this.event}.json`) this.setInput({ - ...this.envDefault, // / add default vars + ...this.envDefault, // add default vars ...{ GITHUB_EVENT_PATH: eventPayload, GITHUB_EVENT_NAME: eventName(this.event) @@ -78,39 +119,16 @@ export class Env ) } - setMocks():void { - this.setGithubMock() - this.setCoreMock() - } - setInput(inputs:{[key:string]: string}):void { process.env = { ...this.envStart, ...inputs} } updateInput(inputs:{[key:string]: string}):void { process.env = { ...process.env, ...formatInput(inputs)} - this.setGithubMock() - } - - setCoreMock():void { - this.coreMock = { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - getInput: jest.fn((name: string, options?: core.InputOptions) => process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`]), - debug: jest.fn(), - warning: jest.fn(), - info: jest.fn(), - error: jest.fn(), - } - jest.mock('@actions/core', () => this.coreMock) - } - - setGithubMock():void { - this.githubMock = { - ...this.octokitMock - } as unknown as GitHub - this.contextMock = new Context() - jest.mock('@actions/github', () => ( - { GitHub: jest.fn(() => this.githubMock), - context: this.contextMock})) + ;({ + github: this.githubMock, + octokit: this.octokitMock, + context: this.context + } = mockGitHub()) } } \ No newline at end of file diff --git a/src/tests/mocks/env/payloads.ts b/src/tests/mocks/env/payloads.ts deleted file mode 100644 index d10d1644..00000000 --- a/src/tests/mocks/env/payloads.ts +++ /dev/null @@ -1,221 +0,0 @@ -// Imports -import { Inferred } from 'typings/Inferred' -import { TestInput } from 'typings/TestInput' -import * as p from '../octokit/payloads' - -export function getTestEvents(inputs: any, event: string): any[][] { - const ret: any[][] = [] - inputs.forEach((test: any) => { - if (typeof test.events === 'string' && test.events === 'all') ret.push(test.inputs) // add for all events - else if (typeof test.events === 'string' && test.events === event) ret.push(test.inputs) // add for named event - else if (Array.isArray(test.events) && test.events.includes(event)) ret.push(test.inputs) // add for named event in list - }) - return ret -} -/** - * Events to Test - */ -export const testEvents: string[] = [ - 'issue_comment_created', - 'issue_comment_edited', - 'pull_request_opened', - 'pull_request_reopened', - 'pull_request_synchronize', - 'push_merge', - 'push', - 'schedule' -] - -/** - * main Test inputs - */ -export const mainTestInputs: TestInput[] = [ - -] -/** - * GithubHelper Test inputs - */ -export const initClientTestInputs: TestInput[] = [ - { inputs: ['calls the Github client constructor with a token', '12345abcde', '12345abcde'], events: 'all' } -] -export const getChangedPRFilesTestInputs: TestInput[] = [ - { inputs: ['gets changed files for a pull request', - { owner: 'trilom', repo: 'file-changes-action', pullNumber: 80 }, - p.OctokitPaginatePrResponse], events: 'all'}, - { inputs: ['throws an error with no pull request', - { owner: 'trilom', repo: 'file-changes-action', pullNumber: NaN }, - {}], events: 'all'}, - { inputs: ['throws an error with invalid repo for pull request', - { owner: 'trilom', repo: 'file-chandkdk-action-thatdoesntreallyexist', pullNumber: 80 }, - {}], events: 'all'}, - { inputs: ['throws an error with invalid owner for pull request', - { owner: 'this-isntareal-githubowner', repo: 'file-changes-action', pullNumber: 80 }, - {}], events: 'all'} -] -export const getChangedPushFilesTestInputs: TestInput[] = [ - { inputs: ['gets changed files for a push', - { owner: 'trilom', repo: 'file-changes-action', before: 'abcd1234', after: '1234abcd' }, - p.OctokitPaginatePushResponse], events: 'all'}, - { inputs: ['throws an error with no before for a push', - { owner: 'trilom', repo: 'file-changes-action', before: '', after: '1234abcd' }, - {}], events: 'all'}, - { inputs: ['throws an error with no after for a push', - { owner: 'trilom', repo: 'file-changes-action', before: '1234abcd', after: '' }, - {}], events: 'all'}, - { inputs: ['throws an error with invalid repo for a push', - { owner: 'trilom', repo: 'file-chandkdk-action-thatdoesntreallyexist', before: 'abcd1234', after: '1234abcd' }, - {}], events: 'all'}, - { inputs: ['throws an error with invalid owner for a push', - { owner: 'this-isntareal-githubowner', repo: 'file-changes-action', before: 'abcd1234', after: '1234abcd' }, - {}], events: 'all'} -] -export const getChangedFilesTestInputs: TestInput[] = [ - { inputs: ['gets changed files for a push', - { repo: 'trilom/file-changes-action', ...{ before: 'abcd1234', after: '1234abcd' } as Inferred }, - p.OctokitPaginatePushResponse], events: 'all'}, - { inputs: ['throws an error with a malformed owner/repo for a push', - { repo: 'trilom/testing/afew/backslash', ...{ before: 'abcd1234', after: '1234abcd' } as Inferred }, - {}], events: 'all'}, - { inputs: ['throws an error with invalid owner for a push', - { repo: 'trilom-NOTREAL/backslash', ...{ before: 'abcd1234', after: '1234abcd' } as Inferred }, - {}], events: 'all'}, - { inputs: ['throws an error with no after for a push', - { repo: 'trilom/cloudformation', ...{ before: 'abcd1234' } as Inferred }, - {}], events: 'all'}, - { inputs: ['throws an error with no before for a push', - { repo: 'trilom/cloudformation', ...{ after: 'abcd1234' } as Inferred }, - {}], events: 'all'}, - { inputs: ['gets changed files for a pull request', - { repo: 'trilom/file-changes-action', ...{ pr: 80 } as Inferred }, - p.OctokitPaginatePrResponse], events: 'all'}, - { inputs: ['throws an error with a malformed owner/repo for a pr', - { repo: 'trilom/testing/afew/backslash', ...{ pr: 80 } as Inferred }, - {}], events: 'all'}, - { inputs: ['throws an error with invalid owner for a pr', - { repo: 'trilom-NOTREAL/backslash', ...{ pr: 80 } as Inferred }, - {}], events: 'all'}, - { inputs: ['throws an error with no pull request', - { repo: 'trilom/cloudformation', ...{ } as Inferred }, - {}], events: 'all'} -] -/** - * InputHelper Test inputs - */ -export const inputTestInputs: TestInput[] = [ - { inputs: ['githubRepo', 'trilom-test/file-changes-action', 'trilom-test/file-changes-action'], events: 'all' }, - { inputs: ['githubToken', 'InputTestToken', 'InputTestToken'], events: "all" }, - { inputs: ['pushBefore', 'abcd1234', 'abcd1234'], events: "all" }, - { inputs: ['pushAfter', '1234abcd', '1234abcd'], events: "all" }, - { inputs: ['prNumber', '1', 1], events: "all" }, - { inputs: ['output', 'json', 'json'], events: "all" }, - { inputs: ['fileOutput', 'json', 'json'], events: "all" } -] -export const inferTestInputs: TestInput[] = [ - { inputs: ['sets PUSH inferred outputs with pr inputs and PUSH inputs and PULL_REQUEST event', - { event: 'pull_request', before: '1234abcd', after: 'abcd1234', pr: 3 }, - { before: '1234abcd', after: 'abcd1234' } as Inferred], - events: ['pull_request_opened', 'pull_request_reopened', 'pull_request_synchronize']}, - {inputs: ['sets PULL_REQUEST inferred outputs with single PUSH input and PULL_REQUEST event, ALSO WARN weird', - { event: 'pull_request', before: '1234abcd', after: '', pr: 2 }, - { pr: 2 } as Inferred], - events: ['pull_request_opened', 'pull_request_reopened', 'pull_request_synchronize']}, - {inputs: ['sets PULL_REQUEST inferred outputs with no PUSH inputs and PULL_REQUEST event', - { event: 'pull_request', before: '', after: '', pr: 4 }, - { pr: 4 } as Inferred], - events: ['pull_request_opened', 'pull_request_reopened', 'pull_request_synchronize']}, - {inputs: ['sets PULL_REQUEST inferred outputs with pr input and PUSH event', - { event: 'push', before: 'abcd12345', after: '12345abcd', pr: 1 }, - { pr: 1 } as Inferred], - events: ['push', 'push_merge']}, - {inputs: ['sets PUSH inferred outputs with no pr input and PUSH event', - { event: 'push', before: 'abcd1234', after: '1234abcd', pr: NaN }, - { before: 'abcd1234', after: '1234abcd' } as Inferred], - events: ['push', 'push_merge']}, - {inputs: ['sets PUSH inferred outputs with PUSH and PULL_REQUEST inputs NOT PUSH or PULL_REQUEST event, ALSO WARN all', - { event: 'schedule', before: 'abcd12345', after: '12345abcd', pr: 1 }, - { before: 'abcd12345', after: '12345abcd' } as Inferred], - events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, - {inputs: ['sets PULL_REQUEST inferred outputs with single PUSH and PULL_REQUEST inputs NOT PUSH or PULL_REQUEST event, ALSO WARN weird', - { event: 'schedule', before: '', after: 'abcd12345', pr: 3 }, - { pr: 3 } as Inferred], - events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, - { - inputs: ['sets PULL_REQUEST inferred outputs with PULL_REQUEST input NOT PUSH or PULL_REQUEST event', - { event: 'schedule', before: '', after: '', pr: 44 }, - { pr: 44 } as Inferred], - events: ['issue_comment_created', 'issue_comment_edited', 'schedule'] - }, - { - inputs: ['sets PUSH inferred outputs with PUSH inputs NOT PUSH or PULL_REQUEST event', - { event: 'schedule', before: 'abcd12345', after: '12345abcd', pr: NaN }, - { before: 'abcd12345', after: '12345abcd', pr: 44 } as Inferred], - events: ['issue_comment_created', 'issue_comment_edited', 'schedule'] - }, - { - inputs: ['throws ERROR with no inputs NOT PUSH or PULL_REQUEST event', - { before: '', after: '', pr: NaN }, - {} as Inferred], - events: ['issue_comment_created', 'issue_comment_edited', 'schedule'] - } -] -/** - * FilesHelper Test inputs - */ -export const sortChangedFilesInputs: TestInput[] = [ - { inputs: ['json', 'json', '.json'], events: 'push' }, - { inputs: ['csv', ',', '.csv'], events: 'push' }, - { inputs: ['txt', ' ', '.txt'], events: 'push' }, - { inputs: ['txt', '_
  _', '.txt'], events: 'push' } -] -export const getOutputInputs: TestInput[] = [ - { - inputs: ['set output string to specified output format for ChangedFiles Object', - [ - { - inputs: [`sets json payloads to JSON.stringify()`, - { format: 'json', changedFiles: p.normalFileArray }, 'json'], events: "push" - }, - { - inputs: [`sets single spaced payloads to files.join(" ")`, - { format: ' ', changedFiles: p.normalFileArray }, ' '], events: "push" - }, - { - inputs: [`sets comma spaced payloads to files.join(",")`, - { format: ',', changedFiles: p.normalFileArray }, ','], events: "push" - }, - { - inputs: [`sets _
  _ spaced payloads to files.join("_
  _")`, - { format: '_
  _', changedFiles: p.normalFileArray }, '_
  _'], events: "push" - } - ], {} - ], - events: "push" - } -] -export const writeOutputInputs: TestInput[] = [ - { - inputs: ['sets core.setOutput outputs with specified format', - { format: 'json', changedFiles: {} }, - {}], - events: "push" - } -] -export const getFormatExtInputs: TestInput[] = [ - { inputs: ['json', 'json', '.json'], events: 'push' }, - { inputs: ['csv', ',', '.csv'], events: 'push' }, - { inputs: ['txt', ' ', '.txt'], events: 'push' }, - { inputs: ['txt', '_
  _', '.txt'], events: 'push' } -] -export const formatChangedFilesInput : TestInput[] = [ - { inputs: [ {type:'normal', format:'json'}, p.normalFileArray, JSON.stringify(p.normalFileArray)], events: 'push' }, - { inputs: [ {type:'normal', format:','}, p.normalFileArray, p.normalFileArray.join(',')], events: 'push' }, - { inputs: [ {type:'normal', format:' '}, p.normalFileArray, p.normalFileArray.join(' ')], events: 'push' }, - { inputs: [ {type:'normal', format:'_
  _'}, p.normalFileArray, p.normalFileArray.join('_
  _')], events: 'push' }, - { inputs: [ {type:'weird', format:'json'}, p.weirdFileArray, JSON.stringify(p.weirdFileArray)], events: 'push' }, - { inputs: [ {type:'weird', format:','}, p.weirdFileArray, p.weirdFileArray.join(',')], events: 'push' }, - { inputs: [ {type:'weird', format:' '}, p.weirdFileArray, p.weirdFileArray.join(' ')], events: 'push' }, - { inputs: [ {type:'weird', format:'_
  _'}, p.weirdFileArray, p.weirdFileArray.join('_
  _')], events: 'push' } -] -/** - * UtilsHelper Test inputs - */ \ No newline at end of file diff --git a/src/tests/mocks/fs/index.test.ts b/src/tests/mocks/fs/index.test.ts new file mode 100644 index 00000000..6a55954e --- /dev/null +++ b/src/tests/mocks/fs/index.test.ts @@ -0,0 +1,23 @@ +import {mock} from '.' + +const fs = mock() + +describe('Testing FsMock object...', () => { + beforeAll(() => jest.restoreAllMocks()) + it('...FsMock is a mock', () => { + expect(jest.isMockFunction(fs.writeFileSync)).toBe(true) + }) + it('...FsMock mocks fs', () => { + const realFs = require('fs') + expect(fs).toMatchObject(realFs) + }) + it('...FsMock mocks writeFileSync', () => { + fs.writeFileSync('a','b','c') + expect(fs.writeFileSync).toBeCalledWith('a','b','c') + }) + it('...FsMock mocks an error', async () => { + expect(() => + fs.writeFileSync('error','b','c')).toThrowError( + new Error(JSON.stringify({ name: 'PathError', status: '500' }))) + }) +}) \ No newline at end of file diff --git a/src/tests/mocks/fs/index.ts b/src/tests/mocks/fs/index.ts new file mode 100644 index 00000000..45481be2 --- /dev/null +++ b/src/tests/mocks/fs/index.ts @@ -0,0 +1,14 @@ +import type {FsMock} from 'typings/FsMock' + +const fsMock = { + writeFileSync: jest.fn( (path, data, options ) => { + if (path === 'error') + throw new Error(JSON.stringify({ name: 'PathError', status: '500' })) + // console.log(`fs.writeFileSync triggered with path: ${path} data: ${data} options: ${options}`) + }) +} + +export function mock():FsMock { + jest.mock('fs', () => fsMock) + return fsMock +} \ No newline at end of file diff --git a/src/tests/mocks/github/index.test.ts b/src/tests/mocks/github/index.test.ts new file mode 100644 index 00000000..f197cb7b --- /dev/null +++ b/src/tests/mocks/github/index.test.ts @@ -0,0 +1,29 @@ +import { Context } from '@actions/github/lib/context' +import {mock} from '.' +import {octokitMock} from '../octokit' + +const github = mock() + +describe('Testing GitHubMock object ...', () => { + beforeAll(() => jest.restoreAllMocks()) + it('...GitHubMock is a mock', () => { + expect(jest.isMockFunction(github.github.GitHub)).toBe(true) + expect(github.context).toMatchObject(new Context) + }) + it('...GitHubMock mocks GitHub', () => { + const {GitHub} = require('@actions/github') + const mockGitHub = GitHub('test') + expect(mockGitHub).toMatchObject(octokitMock) + }) + it('...GitHubMock mocks unauthorized GitHub', () => { + const GitHub = mock() + expect(jest.isMockFunction(GitHub.github.GitHub)).toBe(true) + }) + it('...GitHubMock mocks authorizing GitHub', () => { + const GitHub = mock() + const octokit = GitHub.github.GitHub('token') + expect(jest.isMockFunction(GitHub.github.GitHub)).toBe(true) + expect(GitHub.github.GitHub).toBeCalledWith('token') + expect(octokit).toMatchObject(octokitMock) + }) +}) diff --git a/src/tests/mocks/github/index.ts b/src/tests/mocks/github/index.ts new file mode 100644 index 00000000..2adfba91 --- /dev/null +++ b/src/tests/mocks/github/index.ts @@ -0,0 +1,23 @@ +import { Context } from '@actions/github/lib/context' +import type { GitHubMock } from 'typings/GitHubMock' +import type { OctokitMock } from 'typings/OctokitMock' +import { octokitMock } from '../octokit' + +function getGitHubMock(context: Context):GitHubMock { + return { + GitHub: jest.fn((token) => { + // console.log(`I am authorizing GitHub with token: ${token}`) + if (!token) + throw new Error(JSON.stringify({ name: 'GithubInitError', status: '500' })) + return octokitMock + }), + context + } +} + +export function mock():{github:GitHubMock, octokit: OctokitMock, context: Context} { + const context = new Context() + const github = getGitHubMock(context) + jest.mock('@actions/github', () => github) + return { github, octokit: octokitMock, context } +} \ No newline at end of file diff --git a/src/tests/mocks/octokit/endpoint/merge.test.ts b/src/tests/mocks/octokit/endpoint/merge.test.ts new file mode 100644 index 00000000..a0215698 --- /dev/null +++ b/src/tests/mocks/octokit/endpoint/merge.test.ts @@ -0,0 +1,45 @@ +import type { EndpointOptions } from '@octokit/types' +import {fn as merge} from './merge' +import { + OctokitPullsListFilesEndpointMergeRequest, + OctokitPullsListFilesEndpointMergeResponse, + OctokitReposCompareCommitsEndpointMergeRequest, + OctokitReposCompareCommitsEndpointMergeResponse +} from '../payloads' + +describe('Testing Octokit object...', () => { + beforeAll(() => { jest.restoreAllMocks() }) + it('...endpoint.merge returns 500 error with pull_number "error"', () => { + expect(() => { + merge({pull_number:'error'} as unknown as EndpointOptions) + }).toThrowError(new Error(JSON.stringify( + { name: 'HttpError', + status: '500'}))) + }) + it('...endpoint.merge returns 500 error with base "error"', () => { + expect(() => { + merge({base:'error'} as unknown as EndpointOptions) + }).toThrowError(new Error(JSON.stringify( + { name: 'HttpError', + status: '500'}))) + }) + it('...endpoint.merge returns empty object', async () => { + const request = OctokitPullsListFilesEndpointMergeRequest + const data = merge({...request, pull_number:NaN}) + expect(data).toStrictEqual({ + ...OctokitPullsListFilesEndpointMergeResponse, + ...{pull_number:NaN, base: '', head: ''}}) + }) + it('...endpoint.merge for pull request', () => { + const request = OctokitPullsListFilesEndpointMergeRequest + const response = OctokitPullsListFilesEndpointMergeResponse + const data = merge(request) + expect(data).toStrictEqual(response) + }) + it('...endpoint.merge for push', () => { + const request = OctokitReposCompareCommitsEndpointMergeRequest + const response = OctokitReposCompareCommitsEndpointMergeResponse + const data = merge(request) + expect(data).toStrictEqual(response) + }) +}) diff --git a/src/tests/mocks/octokit/endpoint/merge.ts b/src/tests/mocks/octokit/endpoint/merge.ts index 18838ca3..0ae9b4c6 100644 --- a/src/tests/mocks/octokit/endpoint/merge.ts +++ b/src/tests/mocks/octokit/endpoint/merge.ts @@ -10,11 +10,20 @@ import { export { OctokitReposCompareCommitsEndpointMergeResponse as pushResponse } export { OctokitPullsListFilesEndpointMergeResponse as prResponse } // Export mock function -export const fn = jest.fn((data: EndpointOptions ) => { +export const fn = jest.fn((data: EndpointOptions, response?: number ) => { + if (data.base === 'error' || data.pull_number === 'error') { + throw new Error(JSON.stringify({ name: 'HttpError', status: '500' })) + } + if (data.base === 'unknown' || data.pull_number === 'unknown') { + throw JSON.stringify({ idk: 'error', message: 'test' }) + } if ( (!data.base && !data.head && Number.isNaN(data.pull_number)) || (!data.base && data.head) || - (data.base && !data.head)) return {...OctokitPullsListFilesEndpointMergeResponse, ...{pull_number: NaN, base: '', head: ''}} as RequestOptions + (data.base && !data.head)) + return { + ...OctokitPullsListFilesEndpointMergeResponse, + ...{pull_number: NaN, base: '', head: ''}} as RequestOptions if (data.pull_number) { return {...OctokitPullsListFilesEndpointMergeResponse, ...data} as RequestOptions } diff --git a/src/tests/mocks/octokit/index.test.ts b/src/tests/mocks/octokit/index.test.ts new file mode 100644 index 00000000..4868b42d --- /dev/null +++ b/src/tests/mocks/octokit/index.test.ts @@ -0,0 +1,11 @@ +import {octokitMock} from '.' + +describe('Testing Octokit object ...', () => { + beforeAll(() => jest.restoreAllMocks()) + it('...Octokit is a mock', () => { + expect(octokitMock).toHaveProperty('paginate') + expect(octokitMock).toHaveProperty('pulls') + expect(octokitMock).toHaveProperty('repos') + expect(octokitMock).not.toHaveProperty('actions') + }) +}) diff --git a/src/tests/mocks/octokit/paginate.test.ts b/src/tests/mocks/octokit/paginate.test.ts new file mode 100644 index 00000000..a7b9bef3 --- /dev/null +++ b/src/tests/mocks/octokit/paginate.test.ts @@ -0,0 +1,51 @@ +import {fn as paginate} from './paginate' +import { + OctokitPaginatePrRequest, + OctokitPaginatePrResponse, + OctokitPaginatePushRequest, + OctokitPaginatePushResponse +} from './payloads' + +describe('Testing Octokit object...', () => { + beforeAll(() => { jest.restoreAllMocks() }) + it('...paginate(request) throws a 404', async () => { + const request = OctokitPaginatePrRequest + await expect(paginate({...request, pull_number:NaN})).rejects.toMatchObject({ name: 'HttpError', status: '404' }) + }) + it('...paginate(request) for pull request', () => { + const request = OctokitPaginatePrRequest + const response = OctokitPaginatePrResponse + return paginate(request).then(data => { + expect(data).toStrictEqual(response) + return expect(data.length).toBe(7) + }) + }) + it('...paginate(request, callback) for pull request', () => { + const request = OctokitPaginatePrRequest + const response = OctokitPaginatePrResponse + return paginate(request, res => { + return res.data + }).then(data => { + expect(data).toStrictEqual(response) + return expect(data.length).toBe(7) + }) + }) + it('...paginate(request) for push', async () => { + const request = OctokitPaginatePushRequest + const response = OctokitPaginatePushResponse + expect.assertions(1) + const files = await paginate(request).then(data => { + return data.map(commit => commit.files) + }) + expect(files).toStrictEqual([response]) + }) + it('...paginate(request, callback) for push', async () => { + const request = OctokitPaginatePushRequest + const response = OctokitPaginatePushResponse + const files = await paginate(request, res => { + return res.data.files + }) + expect(files).toStrictEqual(response) + expect(files.length).toBe(7) + }) +}) diff --git a/src/tests/mocks/octokit/pulls/listFiles.test.ts b/src/tests/mocks/octokit/pulls/listFiles.test.ts new file mode 100644 index 00000000..5b1009aa --- /dev/null +++ b/src/tests/mocks/octokit/pulls/listFiles.test.ts @@ -0,0 +1,18 @@ + +import {fn as listFiles} from './listFiles' +import { + OctokitPullsListFilesRequest, + OctokitPullsListFilesResponse +} from '../payloads' + +describe('Testing Octokit object...', () => { + beforeAll(() => { jest.restoreAllMocks() }) + it('...pulls.listFiles(request) for pull request', () => { + const request = OctokitPullsListFilesRequest + const response = OctokitPullsListFilesResponse + return listFiles(request).then(data => { + expect(data.data).toBe(response) + return expect(data.data.length).toBe(7) + }) + }) +}) diff --git a/src/tests/mocks/octokit/pulls/listFiles.ts b/src/tests/mocks/octokit/pulls/listFiles.ts index cc1a19de..b581f808 100644 --- a/src/tests/mocks/octokit/pulls/listFiles.ts +++ b/src/tests/mocks/octokit/pulls/listFiles.ts @@ -7,7 +7,6 @@ import { // Form and export Response Objects export { OctokitPullsListFilesResponse as response } // Export mock function -// eslint-disable-next-line @typescript-eslint/no-unused-vars export const fn = jest.fn((data: EndpointOptions) => { return Promise.resolve({ data: OctokitPullsListFilesResponse diff --git a/src/tests/mocks/octokit/repos/compareCommits.test.ts b/src/tests/mocks/octokit/repos/compareCommits.test.ts new file mode 100644 index 00000000..1f49f837 --- /dev/null +++ b/src/tests/mocks/octokit/repos/compareCommits.test.ts @@ -0,0 +1,18 @@ + +import {fn as compareCommits} from './compareCommits' +import { + OctokitReposCompareCommitsRequest, + OctokitReposCompareCommitsResponse +} from '../payloads' + +describe('Testing Octokit object...', () => { + beforeAll(() => { jest.restoreAllMocks() }) + it('...repos.compareCommits(request) for push', () => { + const request = OctokitReposCompareCommitsRequest + const response = OctokitReposCompareCommitsResponse + return compareCommits(request).then(data => { + expect(data.data.files).toBe(response) + return expect(data.data.files.length).toBe(7) + }) + }) +}) diff --git a/src/tests/mocks/octokit/repos/compareCommits.ts b/src/tests/mocks/octokit/repos/compareCommits.ts index a542b4aa..d1c2eecb 100644 --- a/src/tests/mocks/octokit/repos/compareCommits.ts +++ b/src/tests/mocks/octokit/repos/compareCommits.ts @@ -7,7 +7,6 @@ import { // Form and export Response Objects export { OctokitReposCompareCommitsResponse as response } // Export mock function -// eslint-disable-next-line @typescript-eslint/no-unused-vars export const fn = jest.fn((data: EndpointOptions) => { return Promise.resolve({ data: { diff --git a/src/tests/payloads.ts b/src/tests/payloads.ts new file mode 100644 index 00000000..4966d4d9 --- /dev/null +++ b/src/tests/payloads.ts @@ -0,0 +1,232 @@ +// Imports +import type { Inferred } from 'typings/Inferred' +import type { TestInput } from 'typings/TestInput' +import * as p from './mocks/octokit/payloads' + +/** + * Events to Test + */ +export const testEvents: string[] = [ + 'issue_comment_created', + 'issue_comment_edited', + 'pull_request_opened', + 'pull_request_reopened', + 'pull_request_synchronize', + 'push_merge', + 'push', + 'schedule' +] + +export function changedFilesInput(event: string): TestInput[] { return [ + { inputs: [ {type:'normal', format:'json'}, p.normalFileArray, JSON.stringify(p.normalFileArray)], events: event }, + { inputs: [ {type:'normal', format:','}, p.normalFileArray, p.normalFileArray.join(',')], events: event }, + { inputs: [ {type:'normal', format:' '}, p.normalFileArray, p.normalFileArray.join(' ')], events: event }, + { inputs: [ {type:'normal', format:'_
  _'}, p.normalFileArray, p.normalFileArray.join('_
  _')], events: event }, + { inputs: [ {type:'weird', format:'json'}, p.weirdFileArray, JSON.stringify(p.weirdFileArray)], events: event }, + { inputs: [ {type:'weird', format:','}, p.weirdFileArray, p.weirdFileArray.join(',')], events: event }, + { inputs: [ {type:'weird', format:' '}, p.weirdFileArray, p.weirdFileArray.join(' ')], events: event }, + { inputs: [ {type:'weird', format:'_
  _'}, p.weirdFileArray, p.weirdFileArray.join('_
  _')], events: event } +] +} +/** + * FilesHelper Test inputs + */ +export const getFormatExtInputs: TestInput[] = [ + { inputs: ['json', 'json', '.json'], events: 'push' }, + { inputs: ['csv', ',', '.csv'], events: 'push' }, + { inputs: ['txt', ' ', '.txt'], events: 'push' }, + { inputs: ['txt', '_
  _', '.txt'], events: 'push' } +] +/** + * GithubHelper Test inputs + */ +export const initClientTestInputs: TestInput[] = [ + { inputs: ['calls the Github client constructor with a token', '12345abcde', '12345abcde'], events: 'all' }, + { inputs: ['calls the Github client constructor without a token', '', ''], events: 'all' } +] +export const getChangedPRFilesTestInputs: TestInput[] = [ + { inputs: ['gets changed files for a pull request', + { owner: 'trilom', repo: 'file-changes-action', pullNumber: 80 }, + p.OctokitPaginatePrResponse], events: 'all'}, + { inputs: ['throws an error with no pull request', + { owner: 'trilom', repo: 'file-changes-action', pullNumber: NaN }, + { error: '404/HttpError', from: 'getChangedPRFiles', + message: 'There was an error getting change files for repo:file-changes-action owner:trilom pr:NaN', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with invalid repo for pull request', + { owner: 'trilom', repo: 'file-chandkdk-action-thatdoesntreallyexist', pullNumber: 80 }, + { error: '404/HttpError', from: 'getChangedPRFiles', + message: 'There was an error getting change files for repo:file-chandkdk-action-thatdoesntreallyexist owner:trilom pr:80', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with invalid owner for pull request', + { owner: 'this-isntareal-githubowner', repo: 'file-changes-action', pullNumber: 80 }, + { error: '404/HttpError', from: 'getChangedPRFiles', + message: 'There was an error getting change files for repo:file-changes-action owner:this-isntareal-githubowner pr:80', + payload: {name: 'HttpError', status: '404'}}], events: 'all'} +] +export const getChangedPushFilesTestInputs: TestInput[] = [ + { inputs: ['gets changed files for a push', + { owner: 'trilom', repo: 'file-changes-action', before: 'abcd1234', after: '1234abcd' }, + p.OctokitPaginatePushResponse], events: 'all'}, + { inputs: ['throws an error with no before for a push', + { owner: 'trilom', repo: 'file-changes-action', before: '', after: '1234abcd' }, + { error: '404/HttpError', from: 'getChangedPushFiles', + message: 'There was an error getting change files for repo:file-changes-action owner:trilom base: head:1234abcd', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with no after for a push', + { owner: 'trilom', repo: 'file-changes-action', before: '1234abcd', after: '' }, + { error: '404/HttpError', from: 'getChangedPushFiles', + message: 'There was an error getting change files for repo:file-changes-action owner:trilom base:1234abcd head:', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with invalid repo for a push', + { owner: 'trilom', repo: 'file-chandkdk-action-thatdoesntreallyexist', before: 'abcd1234', after: '1234abcd' }, + { error: '404/HttpError', from: 'getChangedPushFiles', + message: 'There was an error getting change files for repo:file-chandkdk-action-thatdoesntreallyexist owner:trilom base:abcd1234 head:1234abcd', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with invalid owner for a push', + { owner: 'this-isntareal-githubowner', repo: 'file-changes-action', before: 'abcd1234', after: '1234abcd' }, + { error: '404/HttpError', from: 'getChangedPushFiles', + message: 'There was an error getting change files for repo:file-changes-action owner:this-isntareal-githubowner base:abcd1234 head:1234abcd', + payload: {name: 'HttpError', status: '404'}}], events: 'all'} +] +export const getChangedFilesTestInputs: TestInput[] = [ + { inputs: ['gets changed files for a push', + { repo: 'trilom/file-changes-action', ...{ before: 'abcd1234', after: '1234abcd' } as Inferred }, + p.OctokitPaginatePushResponse], events: 'all'}, + { inputs: ['throws an error with a malformed owner/repo for a push', + { repo: 'trilom/testing/afew/backslash', ...{ before: 'abcd1234', after: '1234abcd' } as Inferred }, + { error: '500/Unknown Error:Error', from: 'getChangedFiles', + message: 'There was an error getting change files outputs pr: NaN before: abcd1234 after: 1234abcd', + payload: JSON.stringify( + {error: '500/Bad-Repo', + from: 'self', + message: 'Repo input of trilom/testing/afew/backslash has more than 2 length after splitting.', + payload: ''}, null, 2)}], events: 'all'}, + { inputs: ['throws an error with invalid owner for a push', + { repo: 'trilom-NOTREAL/backslash', ...{ before: 'abcd1234', after: '1234abcd' } as Inferred }, + { error: '404/HttpError', from: 'undefined/Error', + message: 'There was an error getting change files for repo:backslash owner:trilom-NOTREAL base:abcd1234 head:1234abcd', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with no after for a push', + { repo: 'trilom/cloudformation', ...{ before: 'abcd1234' } as Inferred }, + { error: '404/HttpError', from: 'undefined/Error', + message: 'There was an error getting change files for repo:cloudformation owner:trilom base:abcd1234 head:', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with no before for a push', + { repo: 'trilom/cloudformation', ...{ after: 'abcd1234' } as Inferred }, + { error: '404/HttpError', from: 'undefined/Error', + message: 'There was an error getting change files for repo:cloudformation owner:trilom base: head:abcd1234', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['gets changed files for a pull request', + { repo: 'trilom/file-changes-action', ...{ pr: 80 } as Inferred }, + p.OctokitPaginatePrResponse], events: 'all'}, + { inputs: ['throws an error with a malformed owner/repo for a pr', + { repo: 'trilom/testing/afew/backslash', ...{ pr: 80 } as Inferred }, + { error: '500/Unknown Error:Error', from: 'getChangedFiles', + message: 'There was an error getting change files outputs pr: 80 before: undefined after: undefined', + payload: JSON.stringify( + {error: '500/Bad-Repo', + from: 'self', + message: 'Repo input of trilom/testing/afew/backslash has more than 2 length after splitting.', + payload: ''}, null, 2)}], events: 'all'}, + { inputs: ['throws an error with invalid owner for a pr', + { repo: 'trilom-NOTREAL/backslash', ...{ pr: 80 } as Inferred }, + { error: '404/HttpError', from: 'undefined/Error', + message: 'There was an error getting change files for repo:backslash owner:trilom-NOTREAL pr:80', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with no pull request', + { repo: 'trilom/cloudformation', ...{ } as Inferred }, + { error: '404/HttpError', from: 'undefined/Error', + message: 'There was an error getting change files for repo:cloudformation owner:trilom base: head:', + payload: {name: 'HttpError', status: '404'}}], events: 'all'}, + { inputs: ['throws an error with no pull request', + { repo: 'trilom/cloudformation', ...{ } as Inferred }, + { error: '404/HttpError', from: 'undefined/Error', + message: 'There was an error getting change files for repo:cloudformation owner:trilom base: head:', + payload: {name: 'HttpError', status: '404'}}], events: 'all'} +] +/** + * InputHelper Test inputs + */ +export const inputTestInputs: TestInput[] = [ + { inputs: ['githubRepo', 'trilom-test/file-changes-action', 'trilom-test/file-changes-action'], events: 'all' }, + { inputs: ['githubToken', 'InputTestToken', 'InputTestToken'], events: "all" }, + { inputs: ['pushBefore', 'abcd1234', 'abcd1234'], events: "all" }, + { inputs: ['pushAfter', '1234abcd', '1234abcd'], events: "all" }, + { inputs: ['prNumber', '1', 1], events: "all" }, + { inputs: ['output', 'json', 'json'], events: "all" }, + { inputs: ['fileOutput', 'json', 'json'], events: "all" } +] +export const inferTestInputs: TestInput[] = [ + { inputs: ['sets PUSH inferred outputs with pr inputs and PUSH inputs and PULL_REQUEST event', + { event: 'pull_request', before: '1234abcd', after: 'abcd1234', pr: 3 }, + { before: '1234abcd', after: 'abcd1234' } as Inferred], + events: ['pull_request_opened', 'pull_request_reopened', 'pull_request_synchronize']}, + { inputs: ['sets PULL_REQUEST inferred outputs with single PUSH input and PULL_REQUEST event, ALSO WARN weird', + { event: 'pull_request', before: '1234abcd', after: '', pr: 2 }, + { pr: 2 } as Inferred], + events: ['pull_request_opened', 'pull_request_reopened', 'pull_request_synchronize']}, + { inputs: ['sets PULL_REQUEST inferred outputs with no PUSH inputs and PULL_REQUEST event', + { event: 'pull_request', before: '', after: '', pr: 4 }, + { pr: 4 } as Inferred], + events: ['pull_request_opened', 'pull_request_reopened', 'pull_request_synchronize']}, + { inputs: ['sets PULL_REQUEST inferred outputs with pr input and PUSH event', + { event: 'push', before: 'abcd12345', after: '12345abcd', pr: 1 }, + { pr: 1 } as Inferred], + events: ['push', 'push_merge']}, + { inputs: ['sets PUSH inferred outputs with no pr input and PUSH event', + { event: 'push', before: 'abcd1234', after: '1234abcd', pr: NaN }, + { before: 'abcd1234', after: '1234abcd' } as Inferred], + events: ['push', 'push_merge']}, + { inputs: ['sets PUSH inferred outputs with PUSH and PULL_REQUEST inputs NOT PUSH or PULL_REQUEST event, ALSO WARN all', + { event: 'schedule', before: 'abcd12345', after: '12345abcd', pr: 1 }, + { before: 'abcd12345', after: '12345abcd' } as Inferred], + events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, + { inputs: ['sets PULL_REQUEST inferred outputs with single PUSH and PULL_REQUEST inputs NOT PUSH or PULL_REQUEST event, ALSO WARN weird', + { event: 'schedule', before: '', after: 'abcd12345', pr: 3 }, + { pr: 3 } as Inferred], + events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, + { inputs: ['sets PULL_REQUEST inferred outputs with PULL_REQUEST input NOT PUSH or PULL_REQUEST event', + { event: 'schedule', before: '', after: '', pr: 44 }, + { pr: 44 } as Inferred], + events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, + { inputs: ['sets PUSH inferred outputs with PUSH inputs NOT PUSH or PULL_REQUEST event', + { event: 'schedule', before: 'abcd12345', after: '12345abcd', pr: NaN }, + { before: 'abcd12345', after: '12345abcd', pr: 44 } as Inferred], + events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, + { inputs: ['throws ERROR with no inputs NOT PUSH or PULL_REQUEST event', + { before: '', after: '', pr: NaN }, + {} as Inferred], + events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, + { inputs: ['throws ERROR with single only before NOT PUSH or PULL_REQUEST event', + { before: 'abcd1234', pr: NaN }, + {} as Inferred], + events: ['issue_comment_created', 'issue_comment_edited', 'schedule']}, + { inputs: ['throws ERROR with single only after NOT PUSH or PULL_REQUEST event', + { after: 'abcd1234', pr: NaN }, + {} as Inferred], + events: ['issue_comment_created', 'issue_comment_edited', 'schedule']} +] +/** + * UtilsHelper Test inputs + */ +export const errorMessageInputs: TestInput[] = [ + { inputs: ['getInputs', JSON.stringify({ name: 'Error', message:'Error', from: 'getInputs'}, null, 2), + 'There was an getting action inputs.'], events: ['push', 'pull_request_synchronize']}, + { inputs: ['inferInput', JSON.stringify({ name: 'Error', message:'Error', from: 'inferInput'}, null, 2), + 'There was an issue inferring inputs to the action.'], events: ['push', 'pull_request_synchronize']}, + { inputs: ['initClient', JSON.stringify({ name: 'Error', message:'Error', from: 'initClient'}, null, 2), + 'There was an issue initilizing the github client.'], events: ['push', 'pull_request_synchronize']}, + { inputs: ['getChangedFiles', JSON.stringify({ name: 'Error', message:'Error', from: 'getChangedFiles'}, null, 2), + 'There was an issue getting changed files from Github.'], events: ['push', 'pull_request_synchronize']}, + { inputs: ['sortChangedFiles', JSON.stringify({ name: 'Error', message:'Error', from: 'sortChangedFiles'}, null, 2), + 'There was an issue sorting changed files from Github.'], events: ['push', 'pull_request_synchronize']}, + { inputs: ['writeFiles', JSON.stringify({ name: 'Error', message:'Error', from: 'writeFiles'}, null, 2), + 'There was an issue writing output files.'], events: ['push', 'pull_request_synchronize']}, + { inputs: ['writeOutput', JSON.stringify({ name: 'Error', message:'Error', from: 'writeOutput'}, null, 2), + 'There was an issue writing output variables.'], events: ['push', 'pull_request_synchronize']} +] +/** + * main Test inputs + */ +export {errorMessageInputs as mainErrorInputs} \ No newline at end of file diff --git a/src/typings/CoreMock/index.d.ts b/src/typings/CoreMock/index.d.ts new file mode 100644 index 00000000..5471c91f --- /dev/null +++ b/src/typings/CoreMock/index.d.ts @@ -0,0 +1,11 @@ +import type {InputOptions} from '@actions/core' + +export interface CoreMock { + setFailed: (message: string) => void + setOutput: (name: string, value: string) => void + getInput: (message: string, options?: InputOptions) => string | undefined + debug: (message:string) => void + warning: (message:string) => void + info: (message:string) => void + error: (message:string) => void +} \ No newline at end of file diff --git a/src/typings/FsMock/index.d.ts b/src/typings/FsMock/index.d.ts new file mode 100644 index 00000000..6284b876 --- /dev/null +++ b/src/typings/FsMock/index.d.ts @@ -0,0 +1,10 @@ +export interface FsMock { + writeFileSync: ( + path: string | number | Buffer | URL, + data: any, + options?: string | { + encoding?: string | null | undefined; + mode?: string | number | undefined; + flag?: string | undefined; + } | null | undefined) => void +} \ No newline at end of file diff --git a/src/typings/GitHubMock/index.d.ts b/src/typings/GitHubMock/index.d.ts new file mode 100644 index 00000000..e1ee62e1 --- /dev/null +++ b/src/typings/GitHubMock/index.d.ts @@ -0,0 +1,7 @@ +import type { Context } from '@actions/github/lib/context' +import type { OctokitMock } from 'typings/OctokitMock' + +export interface GitHubMock { + GitHub: (token: string) => OctokitMock | OctokitMock + context: Context +} \ No newline at end of file diff --git a/src/typings/OctokitMock/index.d.ts b/src/typings/OctokitMock/index.d.ts index 32c7f1db..da23d274 100644 --- a/src/typings/OctokitMock/index.d.ts +++ b/src/typings/OctokitMock/index.d.ts @@ -1,5 +1,5 @@ import type { EndpointOptions, RequestOptions, OctokitResponse } from '@octokit/types' -// define interface + export interface OctokitMock { paginate: ( data: EndpointOptions, diff --git a/src/typings/TestInput/index.d.ts b/src/typings/TestInput/index.d.ts index f2f0522c..163a95fd 100644 --- a/src/typings/TestInput/index.d.ts +++ b/src/typings/TestInput/index.d.ts @@ -1,10 +1,10 @@ -import {Inferred} from 'typings/Inferred' +import type {Inferred} from 'typings/Inferred' /** * @interface TestInput * @param inputs test input to parse. Can be a string array or an array of objects * @param event event to parse input for. */ -interface TestInput { +export interface TestInput { inputs: string[] | object | Inferred[] events: string | string[] } \ No newline at end of file diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..45e9eb0c --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "exclude": [ + "src/tests/**/*" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index da693fe4..bd72ed9a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,4 @@ "src/**/*.ts", "." ], - "exclude": [ - "src/tests/**/*.test.ts" - ] } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 77ef9809..6d5bc991 100644 --- a/yarn.lock +++ b/yarn.lock @@ -420,6 +420,11 @@ dependencies: "@types/node" ">= 8" +"@tootallnate/once@1": + version "1.0.0" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz#9c13c2574c92d4503b005feca8f2e16cc1611506" + integrity sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA== + "@types/babel__core@^7.1.0": version "7.1.6" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.6.tgz#16ff42a5ae203c9af1c6e190ed1f30f83207b610" @@ -613,6 +618,18 @@ acorn@^7.1.1: resolved "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== +agent-base@5: + version "5.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" + integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== + +agent-base@6: + version "6.0.0" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a" + integrity sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw== + dependencies: + debug "4" + ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: version "6.12.0" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" @@ -680,6 +697,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argv@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" + integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= + aria-query@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" @@ -1039,6 +1061,17 @@ co@^4.6.0: resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +codecov@^3.6.5: + version "3.6.5" + resolved "https://registry.npmjs.org/codecov/-/codecov-3.6.5.tgz#d73ce62e8a021f5249f54b073e6f2d6a513f172a" + integrity sha512-v48WuDMUug6JXwmmfsMzhCHRnhUf8O3duqXvltaYJKrO1OekZWpB/eH6iIoaxMl8Qli0+u3OxptdsBOYiD7VAQ== + dependencies: + argv "0.0.2" + ignore-walk "3.0.3" + js-yaml "3.13.1" + teeny-request "6.0.1" + urlgrey "0.4.4" + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -1169,6 +1202,13 @@ data-urls@^1.0.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1176,13 +1216,6 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2028,6 +2061,15 @@ html-escaper@^2.0.0: resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491" integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig== +http-proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -2037,6 +2079,14 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +https-proxy-agent@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" + integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== + dependencies: + agent-base "5" + debug "4" + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -2044,6 +2094,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +ignore-walk@3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + dependencies: + minimatch "^3.0.4" + ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -2763,7 +2820,7 @@ jest@^24.9.0: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: +js-yaml@3.13.1, js-yaml@^3.13.1: version "3.13.1" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -3169,7 +3226,7 @@ nice-try@^1.0.4: resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch@^2.3.0: +node-fetch@^2.2.0, node-fetch@^2.3.0: version "2.6.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== @@ -4134,6 +4191,13 @@ stealthy-require@^1.1.1: resolved "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= +stream-events@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" + integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== + dependencies: + stubs "^3.0.0" + string-length@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" @@ -4224,6 +4288,11 @@ strip-json-comments@^3.0.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== +stubs@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" + integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -4260,6 +4329,17 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +teeny-request@6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.1.tgz#9b1f512cef152945827ba7e34f62523a4ce2c5b0" + integrity sha512-TAK0c9a00ELOqLrZ49cFxvPVogMUFaWY8dUsQc/0CuQPGF+BOxOQzXfE413BAk2kLomwNplvdtMpeaeGWmoc2g== + dependencies: + http-proxy-agent "^4.0.0" + https-proxy-agent "^4.0.0" + node-fetch "^2.2.0" + stream-events "^1.0.5" + uuid "^3.3.2" + test-exclude@^5.2.3: version "5.2.3" resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" @@ -4476,6 +4556,11 @@ urix@^0.1.0: resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +urlgrey@0.4.4: + version "0.4.4" + resolved "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" + integrity sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8= + use@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"