{"id":18586371,"url":"https://github.com/cardinalby/github-action-ts-run-api","last_synced_at":"2025-04-10T13:32:04.523Z","repository":{"id":40781816,"uuid":"446030895","full_name":"cardinalby/github-action-ts-run-api","owner":"cardinalby","description":"Library for GitHub Action integration testing","archived":false,"fork":false,"pushed_at":"2023-11-02T22:13:40.000Z","size":1044,"stargazers_count":55,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-07T03:47:15.752Z","etag":null,"topics":["actions","github-actions","integration-testing","test","test-automation","testing","testing-tools","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cardinalby.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-01-09T08:15:43.000Z","updated_at":"2025-03-18T06:51:01.000Z","dependencies_parsed_at":"2023-11-14T17:49:36.693Z","dependency_job_id":null,"html_url":"https://github.com/cardinalby/github-action-ts-run-api","commit_stats":{"total_commits":60,"total_committers":1,"mean_commits":60.0,"dds":0.0,"last_synced_commit":"ee1b8685fc3361e5f129bc309274eff239269184"},"previous_names":["cardinalby/js-github-action-test-utils"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fgithub-action-ts-run-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fgithub-action-ts-run-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fgithub-action-ts-run-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fgithub-action-ts-run-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cardinalby","download_url":"https://codeload.github.com/cardinalby/github-action-ts-run-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248225709,"owners_count":21068078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actions","github-actions","integration-testing","test","test-automation","testing","testing-tools","typescript"],"created_at":"2024-11-07T00:38:03.222Z","updated_at":"2025-04-10T13:31:59.498Z","avatar_url":"https://github.com/cardinalby.png","language":"TypeScript","readme":"[![test](https://github.com/cardinalby/github-action-ts-run-api/actions/workflows/test.yml/badge.svg)](https://github.com/cardinalby/github-action-ts-run-api/actions/workflows/test.yml)\n[![publish](https://github.com/cardinalby/github-action-ts-run-api/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/cardinalby/github-action-ts-run-api/actions/workflows/npm-publish.yml)\n\n# TypeScript API for GitHub Action execution and integration/functional testing\n\n## Purpose\n\n🔶 Execute your GitHub action **locally** (or at any other environment).\n\n🔶 Write integration and functional tests for an action, run them locally and on CI.\n\n🔶 Have a short feedback loop without pushing and checking an action behaviour at real GitHub runners every time you change it.\n\n## Features\n\n✅ Supports executing JavaScript and Docker actions.\n\n✅ Tested under Windows, Linux and macOS (Intel + Apple Silicon), NodeJS \u003e= 12 locally and on GitHub hosted runners.\n\n✅ Works well with Docker Desktop under Windows and macOS.\n\n✅ Can be used together with any JavaScript test frameworks or alone.\u003cbr\u003e\n\n✅ Can execute an explicitly specified JS file or _main_, _pre_, _post_ script from `action.yml`.\n\n✅ Can execute a separate sync or async JS function, isolating its environment (process env, exitCode and working dir), intercepting _stdout_ and _stderr_ output for effective dependencies mocking.\n\n✅ Has a clear JavaScript API with TypeScript declarations and reasonable defaults\n\n✅ Produces warnings about deprecated Actions commands\n\n### Setting up an action run option includes:\n\n* Inputs. Can read default input values from `action.yml`\n* Saved state\n* Custom environment variables\n* GitHub context\n* GitHub service environment variables\n* Faking GitHub service files (file commands, event payload file)\n* Faking GitHub dirs (workflow, workspace, temp)\n\n### Reading results of an action run includes:\n\n* Reading exit code, stdout and stderr\n* Reading outputs, saved state, warnings, errors, notices and secrets from intercepted stdout\n* Reading exported vars, added paths from faked file commands\n\n## Installation\n\nInstall for use in tests\n```\nnpm i github-action-ts-run-api --save-dev\n```\n\n## Documentation\n\n- [Run targets overview](./docs/run-targets.md)\n  * [Single function target](./docs/run-targets/function.md)\n  * [JavaScript file target](./docs/run-targets/js-file.md)\n  * [Docker target](./docs/run-targets/docker.md)\n- [Run options](./docs/run-options.md)\n- [Run result](./docs/run-result.md)\n- [Run result warnings](./docs/run-result-warnings.md) (**new**! starting from **2.3.0**)\n\n\n### Other information:\n\n* [Testing of GitHub Actions](https://cardinalby.github.io/blog/post/github-actions/testing/1-testing-of-github-actions-intro/) article.\n\n## Quick examples\n\n### Test JS action in a child node process\n\u003cdetails\u003e\n\u003csummary\u003eaction.yml\u003c/summary\u003e\n\n```yaml\nname: 'test'\n# ...\nruns:\n  using: 'node16'\n  main: 'main.js'\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003emain.js:\u003c/summary\u003e\n\n```js\nconst core = require(\"@actions/core\");\nconst context = require('@actions/github').context;\nconst fs = require('fs');\n\ncore.addPath('newPath');\nfs.writeFileSync(\n    path.join(process.env.RUNNER_TEMP, 'f.txt'),\n    context.payload.pull_request.number.toString()\n);\n```\n\n\u003c/details\u003e\n\naction.test.ts:\n```ts\nimport {RunOptions, RunTarget} from 'github-action-ts-run-api';\n\n// You can also test \"pre\" and \"post\" scripts\nconst target = RunTarget.mainJsScript('action.yml');\nconst options = RunOptions.create()\n    // Internally, runner will fake a json file to be picked by @actions/github\n    .setGithubContext({payload: {pull_request: {number: 123}}})\n    // By default, RUNNER_TEMP is faked for a run and then deleted. Keep it\n    .setFakeFsOptions({rmFakedTempDirAfterRun: false});\n\nconst res = await target.run(options);\n\ntry {\n    assert(res.commands.addedPaths === ['newPath']);\n    // somewhere in system temp dir\n    const pathOfCreatedFile = path.join(res.tempDirPath, 'f.txt');\n    // check the contents of a file saved by tested action\n    assert(fs.readFileSync(pathOfCreatedFile).toString() === '123');\n} finally {\n    // we should do it manually because we set rmFakedTempDirAfterRun: false\n    // otherwise it is deleted at the end of target.run()\n    res.cleanUpFakedDirs();\n    \n    // With Jest you can use this instead:\n    // This code also gets executed on test timeout \n    // afterAll(() =\u003e { \n    //     deleteAllFakedDirs(); \n    // });\n}\n```\n\n### Test JavaScript function in isolated Action environment\n\u003cdetails\u003e\n\u003csummary\u003emain.js\u003c/summary\u003e\n\n```js\nconst core = require(\"@actions/core\");\n\nexport async function actionMainFn() {\n    core.setOutput('out1', core.getInput('in1'));\n    core.setOutput('out2', process.env.ENV2);\n    core.exportVariable('v3', core.getState('my_state'));\n    // writes to errors and sets process.exitCode to 1\n    return new Promise(resolve =\u003e setTimeout(() =\u003e {\n        core.setFailed('err1');\n        resolve();\n        }, 1000));    \n}\n```\n\n\u003c/details\u003e\n\nmain.test.ts:\n```ts\nimport {RunOptions, RunTarget} from 'github-action-ts-run-api';\nimport {actionMainFn} from './main.js';\n\n// Will wait until returned promise fulfills. \n// Use RunTarget.syncFn() for regular functions\nconst target = RunTarget.asyncFn(actionMainFn);\nconst options = RunOptions.create()\n    .setInputs({in1: 'abc'})\n    .setEnv({ENV2: 'def'})\n    .setState({my_state: 'ghi'});\n\nconst result = await target.run(options);\n\nassert(result.durationMs \u003e= 1000);\nassert(result.commands.outputs === {out1: 'abc', out2: 'def'});\nassert(result.commands.exportedVars === {v3: 'ghi'});\nassert(result.exitCode === 1);\nassert(result.runnerWarnings.length === 0);\n// changes were isolated inside a function run\nassert(process.exitCode !== 1);\nassert(result.commands.errors === ['err1']);\n```\n\n### Test Docker action\n\n```ts\nimport {RunOptions, RunTarget} from 'github-action-ts-run-api';\n\nconst target = RunTarget.dockerAction('action.yml');\nconst options = RunOptions.create()\n    .setInputs({input1: 'val1', input2: 'val2'})    \n    .setEnv({ENV1: 'val3'})\n    .setWorkingDir('/dir/inside/container')\n    .setTimeoutMs(5000)\n//  ...\nconst res = await target.run(options);\n\nconsole.log(\n    res.commands.outputs,\n    res.commands.exportedVars,\n    res.isSuccessBuild,\n    res.isSuccess,\n    res.isTimedOut\n);\n```\n\n### Integration tests examples:\n\nYou can find **examples** for the complicated cases in the **library** integration **tests**:\n* [Docker target test](./tests/integration/DockerTarget.test.ts)\n* [JS file target test](./tests/integration/JsFileTarget.test.ts)\n* [Function target test](./tests/integration/FnTarget.test.ts)\n\nAlso, check out **real actions** integration **tests**:\n\n* [git-get-release-action](https://github.com/cardinalby/git-get-release-action/blob/master/tests/integration/action.test.ts)\n* [schema-validator-action](https://github.com/cardinalby/schema-validator-action/blob/master/tests/integration/main.test.ts)\n* [js-eval-action](https://github.com/cardinalby/js-eval-action/blob/master/tests/integration/cliAction.test.ts)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcardinalby%2Fgithub-action-ts-run-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcardinalby%2Fgithub-action-ts-run-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcardinalby%2Fgithub-action-ts-run-api/lists"}