├── .dockerignore ├── .eslintignore ├── .eslintrc.json ├── .github ├── dependabot.yml ├── renovate.json └── workflows │ └── nodejs.yml ├── .gitignore ├── .vscode └── settings.json ├── .yarn ├── plugins │ └── @yarnpkg │ │ └── plugin-interactive-tools.cjs └── releases │ └── yarn-3.8.7.cjs ├── .yarnrc ├── .yarnrc.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── babel.config.js ├── generator ├── config.js ├── fixtures │ ├── _README.md │ ├── _package.json │ ├── index.js │ └── run.js └── index.js ├── integrationTests ├── __fixtures__ │ ├── failing │ │ ├── __src__ │ │ │ └── file1.js │ │ └── jest.config.js │ ├── passing │ │ ├── __src__ │ │ │ └── file1.js │ │ └── jest.config.js │ ├── skipped │ │ ├── __src__ │ │ │ └── file1.js │ │ └── jest.config.js │ ├── slow │ │ ├── __src__ │ │ │ └── file1.js │ │ └── jest.config.js │ └── todo │ │ ├── __src__ │ │ └── file1.js │ │ └── jest.config.js ├── __snapshots__ │ ├── failing.test.js.snap │ ├── passing.test.js.snap │ ├── skipped.test.js.snap │ ├── slow.test.js.snap │ └── todo.test.js.snap ├── failing.test.js ├── passing.test.js ├── runJest.js ├── runner │ ├── index.js │ └── run.js ├── skipped.test.js ├── slow.test.js └── todo.test.js ├── jest.config.js ├── lib ├── createJestRunner.ts ├── fail.ts ├── index.ts ├── pass.ts ├── skip.ts ├── toTestResult.ts ├── todo.ts └── types.ts ├── package.json ├── tsconfig.json └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | build 3 | .yarn/ 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "airbnb-base", 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:import/typescript", 6 | "plugin:prettier/recommended" 7 | ], 8 | "plugins": ["jest"], 9 | "rules": { 10 | "import/export": "off", 11 | "import/extensions": [ 12 | "error", 13 | "ignorePackages", 14 | { 15 | "js": "never", 16 | "mjs": "never", 17 | "jsx": "never", 18 | "ts": "never" 19 | } 20 | ], 21 | "max-classes-per-file": "off", 22 | "no-underscore-dangle": "off", 23 | "no-useless-constructor": "off", 24 | "@typescript-eslint/consistent-type-imports": [ 25 | "error", 26 | { "fixStyle": "inline-type-imports" } 27 | ], 28 | "@typescript-eslint/prefer-ts-expect-error": "error" 29 | }, 30 | "env": { 31 | "jest/globals": true 32 | }, 33 | "overrides": [ 34 | { 35 | "files": "generator/**/*", 36 | "rules": { 37 | "import/no-unresolved": "off" 38 | } 39 | }, 40 | { 41 | "files": "integrationTests/__fixtures__/**/*", 42 | "rules": { 43 | "no-console": "off" 44 | } 45 | }, 46 | { 47 | // TODO: remove after migrating to TS 48 | "files": "**/*.js", 49 | "rules": { 50 | "@typescript-eslint/no-var-requires": "off", 51 | "@typescript-eslint/explicit-module-boundary-types": "off" 52 | } 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # https://github.com/dependabot/dependabot-core/issues/1297 4 | # - package-ecosystem: npm 5 | # directory: / 6 | # schedule: 7 | # interval: daily 8 | - package-ecosystem: github-actions 9 | directory: / 10 | schedule: 11 | interval: daily 12 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:base"], 3 | "lockFileMaintenance": { "enabled": true, "automerge": true }, 4 | "rangeStrategy": "replace", 5 | "postUpdateOptions": ["yarnDedupeHighest"] 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - '**' 10 | 11 | jobs: 12 | lint-and-typecheck: 13 | name: ESLint 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: 'lts/*' 21 | cache: yarn 22 | - name: install 23 | run: yarn 24 | - name: build 25 | run: yarn build 26 | - name: build types 27 | run: yarn build-types 28 | - name: run eslint 29 | run: yarn lint 30 | - name: run prettier 31 | run: yarn prettier:check 32 | test-node: 33 | name: Test on Node.js v${{ matrix.node-version }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | node-version: [14.x, 16.x, 18.x, 19.x, 20.x] 38 | runs-on: ubuntu-latest 39 | 40 | steps: 41 | - uses: actions/checkout@v4 42 | - name: Use Node.js ${{ matrix.node-version }} 43 | uses: actions/setup-node@v4 44 | with: 45 | node-version: ${{ matrix.node-version }} 46 | cache: yarn 47 | - name: install 48 | run: yarn 49 | - name: build 50 | run: yarn build 51 | - name: build types 52 | run: yarn build-types 53 | - name: run tests 54 | run: yarn test 55 | test-os: 56 | name: Test on ${{ matrix.os }} using Node.js LTS 57 | strategy: 58 | fail-fast: false 59 | matrix: 60 | os: [ubuntu-latest, windows-latest, macOS-latest] 61 | runs-on: ${{ matrix.os }} 62 | 63 | steps: 64 | - uses: actions/checkout@v4 65 | - uses: actions/setup-node@v4 66 | with: 67 | node-version: 'lts/*' 68 | cache: yarn 69 | - name: install 70 | run: yarn 71 | - name: build 72 | run: yarn build 73 | - name: build types 74 | run: yarn build-types 75 | - name: run tests 76 | run: yarn test 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | projects 3 | yarn-error.log 4 | build 5 | coverage 6 | 7 | # https://yarnpkg.com/advanced/qa#which-files-should-be-gitignored 8 | .yarn/* 9 | !.yarn/releases 10 | !.yarn/plugins 11 | !.yarn/sdks 12 | !.yarn/versions 13 | .pnp.* 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.rulers": [80], 3 | "prettier.printWidth": 80, 4 | "prettier.singleQuote": true, 5 | "prettier.trailingComma": "all", 6 | "prettier.semi": true, 7 | "editor.formatOnSave": true, 8 | "prettier.eslintIntegration": true 9 | } 10 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | lastUpdateCheck 1576854265612 6 | yarn-path ".yarn/releases/yarn-2.4.2.cjs" 7 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | enableGlobalCache: true 2 | 3 | nodeLinker: node-modules 4 | 5 | plugins: 6 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 7 | spec: "@yarnpkg/plugin-interactive-tools" 8 | 9 | yarnPath: .yarn/releases/yarn-3.8.7.cjs 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## main 2 | 3 | ## 0.9.0 4 | 5 | - Migrate source code to TypeScript (should not affect consumers, but marking as new minor just in case) 6 | 7 | ## 0.8.0 8 | 9 | - Drop support for Node 15 10 | - Update `jest-worker` to v27 11 | 12 | ## 0.7.1 13 | 14 | - Ship type definitions 15 | 16 | ## 0.7.0 17 | 18 | - Update dependencies and drop support for Node 8 19 | 20 | ## 0.6.0 21 | 22 | - Update dependencies and drop Node 6 23 | 24 | ## 0.5.0 25 | 26 | ### Features 27 | 28 | - Add support for the new test status `todo`, introduced in Jest 24 ([#14](https://github.com/jest-community/create-jest-runner/pull/14)) 29 | 30 | ### Chore 31 | 32 | - Upgrade to `jest-worker@24` ([#14](https://github.com/jest-community/create-jest-runner/pull/14)) 33 | 34 | ## 0.4.0 35 | 36 | ### Features 37 | 38 | - Add `getExtraOptions` to entry file ([#12](https://github.com/rogeliog/create-jest-runner/pull/12)) 39 | 40 | ### Breaking changes 41 | 42 | - Drop Node 4 ([#4](https://github.com/rogeliog/create-jest-runner/pull/4)) 43 | 44 | ## 0.3.1 45 | 46 | ### Fixes 47 | 48 | - Use a mutex when running in band as well ([#7](https://github.com/rogeliog/create-jest-runner/pull/7)) 49 | - Use import/export ([#8](https://github.com/rogeliog/create-jest-runner/pull/8)) 50 | - Removing un-needed packages ([#1](https://github.com/rogeliog/create-jest-runner/pull/1)) 51 | 52 | ## 0.3.0 53 | 54 | ### Fixes 55 | 56 | - Mutex the workers, to behave more like native jest test runs ([#5](https://github.com/rogeliog/create-jest-runner/pull/5)) 57 | 58 | ### Features 59 | 60 | - Support serial execution ([#6](https://github.com/rogeliog/create-jest-runner/pull/6)) 61 | 62 | ## O.2.0 63 | 64 | ### Features 65 | 66 | - Add skip functionality 67 | 68 | ## O.1.1 69 | 70 | ### Fixes 71 | 72 | - TTY support for jest-worker 73 | 74 | ## 0.1.0 75 | 76 | - Initial Release 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Setup up your dev environment 2 | 3 | 1. Fork the repo and create your branch from `main`. 4 | A guide on how to fork a repository: https://help.github.com/articles/fork-a-repo/ 5 | 6 | Open terminal (e.g. Terminal, iTerm, Git Bash or Git Shell) and type: 7 | 8 | ```sh 9 | git clone https://github.com//jest-runner-utils 10 | cd jest 11 | git checkout -b my_branch 12 | ``` 13 | 14 | Note: 15 | Replace `` with your GitHub username 16 | 17 | 2. jest-runner-utils uses [Yarn](https://code.facebook.com/posts/1840075619545360) 18 | for running development scripts. If you haven't already done so, 19 | please [install yarn](https://yarnpkg.com/en/docs/install). 20 | 21 | 3. Run `yarn`. 22 | 23 | ```sh 24 | yarn 25 | ``` 26 | 27 | 4. If you've changed APIs, update the documentation. 28 | 29 | 5. Ensure the test suite passes via `yarn test`. To run the test suite you 30 | 31 | ```sh 32 | yarn test 33 | ``` 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG NODE_VERSION=20 2 | FROM node:${NODE_VERSION} 3 | 4 | WORKDIR /app 5 | 6 | COPY package.json yarn.lock /app/ 7 | 8 | RUN yarn --ignore-scripts 9 | 10 | COPY . . 11 | 12 | RUN yarn build 13 | 14 | CMD ["yarn", "test"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Rogelio Guzman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # create-jest-runner 2 | 3 | [![Actions Status](https://github.com/jest-community/create-jest-runner/actions/workflows/nodejs.yml/badge.svg?branch=main)](https://github.com/jest-community/create-jest-runner/actions) 4 | 5 | A highly opinionated way for creating Jest Runners 6 | 7 | ## Install 8 | 9 | ```bash 10 | yarn add create-jest-runner 11 | ``` 12 | 13 | ## Usage 14 | 15 | create-jest-runner takes care of handling the appropriate parallelization and creating a worker farm for your runner. 16 | 17 | You simply need two files: 18 | 19 | - Entry file: Used by Jest as an entrypoint to your runner. 20 | - Run file: Runs once per test file, and it encapsulates the logic of your runner 21 | 22 | ### 1) Create your entry file 23 | 24 | ```js 25 | // index.js 26 | const { createJestRunner } = require('create-jest-runner'); 27 | module.exports = createJestRunner(require.resolve('./run')); 28 | ``` 29 | 30 | #### createJestRunner(pathToRunFile, config?: { getExtraOptions }) 31 | 32 | - `pathToRunFile`: path to your run file. This must be an absolute path or a `file://` URL. 33 | - `config`: Optional argument for configuring the runner. 34 | - `getExtraOptions`: `() => object` used for passing extra options to the runner. It needs to be a serializable object because it will be send to a different Node process. 35 | 36 | ### 2) Create your run file 37 | 38 | ```js 39 | module.exports = options => {}; 40 | ``` 41 | 42 | ### Run File API 43 | 44 | This file should export a function that receives one parameter with the options 45 | 46 | #### `options: { testPath, config, globalConfig }` 47 | 48 | - `testPath`: Path of the file that is going to be tests 49 | - `config`: Jest Project config used by this file 50 | - `globalConfig`: Jest global config 51 | - `extraOptions`: The return value of the `{ getExtraOptions }` argument of `createJestRunner(...)` the entry file. 52 | 53 | You can return one of the following values: 54 | 55 | - `testResult`: Needs to be an object of type https://github.com/facebook/jest/blob/4d3c1a187bd429fd8611f6b0f19e4aa486fa2a85/packages/jest-test-result/src/types.ts#L103-L135 56 | - `Promise`: needs to be of above type. 57 | - `Error`: good for reporting system error, not failed tests. 58 | 59 | ## Example of a runner 60 | 61 | This runner "blade-runner" makes sure that these two emojis `⚔️ 🏃` are present in every file 62 | 63 | ```js 64 | // index.js 65 | const { createJestRunner } = require('create-jest-runner'); 66 | module.exports = createJestRunner(require.resolve('./run')); 67 | ``` 68 | 69 | ```js 70 | // run.js 71 | const fs = require('fs'); 72 | const { pass, fail } = require('create-jest-runner'); 73 | 74 | /** @type {import('create-jest-runner').RunTest} */ 75 | const runTest = ({ testPath }) => { 76 | const start = Date.now(); 77 | const contents = fs.readFileSync(testPath, 'utf8'); 78 | const end = Date.now(); 79 | 80 | if (contents.includes('⚔️🏃')) { 81 | return pass({ start, end, test: { path: testPath } }); 82 | } 83 | const errorMessage = 'Company policies require ⚔️ 🏃 in every file'; 84 | return fail({ 85 | start, 86 | end, 87 | test: { path: testPath, errorMessage, title: 'Check for ⚔️ 🏃' }, 88 | }); 89 | }; 90 | 91 | module.exports = runTest; 92 | ``` 93 | 94 | ## Create runner from binary 95 | 96 | ```shell 97 | yarn create jest-runner my-runner 98 | 99 | # Or with npm 100 | npm init jest-runner my-runner 101 | ``` 102 | 103 | **Note:** You will have to update the package name in `package.json` of the generated runner. 104 | 105 | ## Add your runner to Jest config 106 | 107 | Once you have your Jest runner you can add it to your Jest config. 108 | 109 | In your `package.json` 110 | 111 | ```json 112 | { 113 | "jest": { 114 | "runner": "/path/to/my-runner" 115 | } 116 | } 117 | ``` 118 | 119 | Or in `jest.config.js` 120 | 121 | ```js 122 | module.exports = { 123 | runner: '/path/to/my-runner', 124 | }; 125 | ``` 126 | 127 | ### Run Jest 128 | 129 | ```bash 130 | yarn jest 131 | ``` 132 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | 3 | const semver = require('semver'); 4 | const pkg = require('./package.json'); 5 | 6 | const supportedNodeVersion = semver.minVersion(pkg.engines.node).version; 7 | 8 | module.exports = { 9 | presets: [ 10 | ['@babel/preset-env', { targets: { node: supportedNodeVersion } }], 11 | ['@babel/preset-typescript', { allowDeclareFields: true }], 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /generator/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | dirs: ['src'], 3 | createList: [ 4 | { 5 | input: '_package.json', 6 | output: 'package.json', 7 | }, 8 | { 9 | input: '_README.md', 10 | output: 'README.md', 11 | }, 12 | { 13 | input: 'index.js', 14 | output: 'src/index.js', 15 | }, 16 | { 17 | input: 'run.js', 18 | output: 'src/run.js', 19 | }, 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /generator/fixtures/_README.md: -------------------------------------------------------------------------------- 1 | # generated-jest-runner 2 | 3 | ## Usage 4 | 5 | ### Install 6 | 7 | Install `jest`_(it needs Jest 21+)_ and `generated-jest-runner` 8 | 9 | ```bash 10 | yarn add --dev jest generated-jest-runner 11 | 12 | # or with NPM 13 | 14 | npm install --save-dev jest generated-jest-runner 15 | ``` 16 | 17 | ## Add your runner to Jest config 18 | 19 | Once you have your Jest runner you can add it to your Jest config. 20 | 21 | In your `package.json` 22 | 23 | ```json 24 | { 25 | "jest": { 26 | "runner": "generated-jest-runner" 27 | } 28 | } 29 | ``` 30 | 31 | Or in `jest.config.js` 32 | 33 | ```js 34 | module.exports = { 35 | runner: require.resolve('generated-jest-runner'), 36 | }; 37 | ``` 38 | 39 | ### Run Jest 40 | 41 | ```bash 42 | yarn jest 43 | ``` 44 | -------------------------------------------------------------------------------- /generator/fixtures/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generated-jest-runner", 3 | "version": "1.0.0", 4 | "description": "A generated jest runner", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "jest": { 10 | "runner": "./test/runner" 11 | }, 12 | "dependencies": { 13 | "jest": "^24.6.0", 14 | "create-jest-runner": "^0.5.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /generator/fixtures/index.js: -------------------------------------------------------------------------------- 1 | const { createJestRunner } = require('create-jest-runner'); 2 | 3 | module.exports = createJestRunner(require.resolve('./run')); 4 | -------------------------------------------------------------------------------- /generator/fixtures/run.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { pass, fail } = require('create-jest-runner'); 3 | 4 | module.exports = ({ testPath }) => { 5 | const start = Date.now(); 6 | const contents = fs.readFileSync(testPath, 'utf8'); 7 | const end = Date.now(); 8 | 9 | if (contents.includes('⚔️🏃')) { 10 | return pass({ start, end, test: { path: testPath } }); 11 | } 12 | const errorMessage = 'Company policies require ⚔️ 🏃 in every file'; 13 | return fail({ 14 | start, 15 | end, 16 | test: { path: testPath, errorMessage, title: 'Check for ⚔️ 🏃' }, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /generator/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* eslint-disable no-console */ 3 | 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const { blue, red, green, yellow, magenta } = require('chalk'); 7 | const config = require('./config'); 8 | 9 | const createIfNotExists = folder => { 10 | if (!fs.existsSync(folder)) { 11 | console.log(`Creating new jest-runner in ${green(folder)}`); 12 | fs.mkdirSync(folder); 13 | } else { 14 | throw new Error('Folder already exists'); 15 | } 16 | }; 17 | 18 | const scaffoldRunner = () => { 19 | try { 20 | const fixturesPath = path.resolve(__dirname, 'fixtures'); 21 | let outputDirname; 22 | const projectName = process.argv[2]; 23 | if (projectName) { 24 | outputDirname = path.resolve('.', projectName); 25 | createIfNotExists(outputDirname); 26 | } else { 27 | throw new Error('Project name not specified'); 28 | } 29 | 30 | config.dirs.forEach(item => { 31 | console.log(`Creating ${blue('directory')} ${magenta(item)}`); 32 | fs.mkdirSync(path.resolve(outputDirname, item)); 33 | }); 34 | 35 | config.createList.forEach(file => { 36 | const filePath = path.resolve(outputDirname, file.output); 37 | const content = fs.readFileSync(path.resolve(fixturesPath, file.input)); 38 | console.log(`Creating ${yellow('file')} ${magenta(file.output)}`); 39 | fs.writeFileSync(filePath, content); 40 | }); 41 | console.log(green('Scaffolding successfull')); 42 | console.log(blue('Run cd npm/yarn install')); 43 | console.log(red('Update the package name package.json')); 44 | } catch (e) { 45 | console.log(`${red('Scaffolding failed')} ${e}`); 46 | } 47 | }; 48 | 49 | scaffoldRunner(); 50 | 51 | module.exports = { 52 | scaffoldRunner, 53 | }; 54 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/failing/__src__/file1.js: -------------------------------------------------------------------------------- 1 | console.log(); 2 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/failing/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | runner: require.resolve('../../runner'), 3 | testMatch: ['**/__src__/**/*.js'], 4 | }; 5 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/passing/__src__/file1.js: -------------------------------------------------------------------------------- 1 | // ⚔️🏃 2 | console.log(); 3 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/passing/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | runner: require.resolve('../../runner'), 3 | testMatch: ['**/__src__/**/*.js'], 4 | }; 5 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/skipped/__src__/file1.js: -------------------------------------------------------------------------------- 1 | // 🙈 2 | console.log(); 3 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/skipped/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | runner: require.resolve('../../runner'), 3 | testMatch: ['**/__src__/**/*.js'], 4 | }; 5 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/slow/__src__/file1.js: -------------------------------------------------------------------------------- 1 | // ⚔️🏃 2 | console.log(); 3 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/slow/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | runner: require.resolve('../../runner'), 3 | testMatch: ['**/__src__/**/*.js'], 4 | slowTestThreshold: -1, // Set this to negative so all tests are slow 5 | }; 6 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/todo/__src__/file1.js: -------------------------------------------------------------------------------- 1 | // 📃 2 | console.log(); 3 | -------------------------------------------------------------------------------- /integrationTests/__fixtures__/todo/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | runner: require.resolve('../../runner'), 3 | testMatch: ['**/__src__/**/*.js'], 4 | }; 5 | -------------------------------------------------------------------------------- /integrationTests/__snapshots__/failing.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Works when it has failing tests 1`] = ` 4 | "FAIL integrationTests/__fixtures__/failing/__src__/file1.js 5 | ✕ Check for ⚔️ 🏃 6 | Company policies require ⚔️ 🏃 in every file 7 | Test Suites: 1 failed, 1 total 8 | Tests: 1 failed, 1 total 9 | Snapshots: 0 total 10 | Time: 11 | Ran all test suites. 12 | " 13 | `; 14 | -------------------------------------------------------------------------------- /integrationTests/__snapshots__/passing.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Works when it has only passing tests 1`] = ` 4 | "PASS integrationTests/__fixtures__/passing/__src__/file1.js 5 | ✓ 6 | Test Suites: 1 passed, 1 total 7 | Tests: 1 passed, 1 total 8 | Snapshots: 0 total 9 | Time: 10 | Ran all test suites. 11 | " 12 | `; 13 | -------------------------------------------------------------------------------- /integrationTests/__snapshots__/skipped.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Works when it has skipped tests 1`] = ` 4 | "Test Suites: 1 skipped, 0 of 1 total 5 | Tests: 1 skipped, 1 total 6 | Snapshots: 0 total 7 | Time: 8 | Ran all test suites. 9 | " 10 | `; 11 | -------------------------------------------------------------------------------- /integrationTests/__snapshots__/slow.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Works when it has slow tests 1`] = ` 4 | "PASS integrationTests/__fixtures__/slow/__src__/file1.js () 5 | ✓ 6 | Test Suites: 1 passed, 1 total 7 | Tests: 1 passed, 1 total 8 | Snapshots: 0 total 9 | Time: 10 | Ran all test suites. 11 | " 12 | `; 13 | -------------------------------------------------------------------------------- /integrationTests/__snapshots__/todo.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Works when it has todo tests 1`] = ` 4 | "PASS integrationTests/__fixtures__/todo/__src__/file1.js 5 | ✓ 6 | Test Suites: 1 passed, 1 total 7 | Tests: 1 todo, 1 total 8 | Snapshots: 0 total 9 | Time: 10 | Ran all test suites. 11 | " 12 | `; 13 | -------------------------------------------------------------------------------- /integrationTests/failing.test.js: -------------------------------------------------------------------------------- 1 | const runJest = require('./runJest'); 2 | 3 | it('Works when it has failing tests', () => 4 | expect(runJest('failing')).resolves.toMatchSnapshot()); 5 | -------------------------------------------------------------------------------- /integrationTests/passing.test.js: -------------------------------------------------------------------------------- 1 | const runJest = require('./runJest'); 2 | 3 | it('Works when it has only passing tests', () => 4 | expect(runJest('passing')).resolves.toMatchSnapshot()); 5 | -------------------------------------------------------------------------------- /integrationTests/runJest.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | // eslint-disable-next-line import/no-extraneous-dependencies 3 | const execa = require('execa'); 4 | // eslint-disable-next-line import/no-extraneous-dependencies 5 | const stripAnsi = require('strip-ansi'); 6 | 7 | const rootDir = path.resolve(__dirname, '..'); 8 | 9 | const normalize = output => 10 | stripAnsi(output) 11 | .replace(/\d*\.?\d+ m?s\b/g, '') 12 | .replace(/, estimated/g, '') 13 | .replace(new RegExp(rootDir, 'g'), '/mocked-path-to-jest-runner-mocha') 14 | .replace(/.*at .*\n/g, 'mocked-stack-trace') 15 | .replace(/.*at .*\\n/g, 'mocked-stack-trace') 16 | .replace(/(mocked-stack-trace)+/, ' at mocked-stack-trace') 17 | .replace(/\s+\n/g, '\n') 18 | // https://github.com/facebook/jest/blob/a8addf8e22ef74b2ff3a139ece098604ec46b6e7/packages/jest-util/src/specialChars.ts#L11-L16 19 | .replace(/\u00D7/g, '\u2715') 20 | .replace(/\u221A/g, '\u2713'); 21 | 22 | const runJest = (project, options = []) => { 23 | // eslint-disable-next-line 24 | jest.setTimeout(15000); 25 | return execa( 26 | 'jest', 27 | [ 28 | '--useStderr', 29 | '--no-watchman', 30 | '--no-cache', 31 | '--projects', 32 | path.join(__dirname, '__fixtures__', project), 33 | ].concat(options), 34 | { 35 | env: process.env, 36 | reject: false, 37 | }, 38 | ).then(({ stdout, stderr }) => `${normalize(stderr)}\n${normalize(stdout)}`); 39 | }; 40 | 41 | module.exports = runJest; 42 | -------------------------------------------------------------------------------- /integrationTests/runner/index.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/extensions, import/no-unresolved -- ignore build artifact 2 | const { createJestRunner } = require('../..'); 3 | 4 | module.exports = createJestRunner(require.resolve('./run')); 5 | -------------------------------------------------------------------------------- /integrationTests/runner/run.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | // eslint-disable-next-line import/extensions, import/no-unresolved -- ignore build artifact 3 | const { pass, fail, skip, todo } = require('../..'); 4 | 5 | /** @type {import('../..').RunTest} */ 6 | const runTest = ({ testPath }) => { 7 | const start = Date.now(); 8 | // we don't want the timestamp in the reporter result for our snapshots 9 | const end = start; 10 | const contents = fs.readFileSync(testPath, 'utf8'); 11 | 12 | if (contents.includes('⚔️🏃')) { 13 | return pass({ start, end, test: { path: testPath } }); 14 | } 15 | if (contents.includes('🙈')) { 16 | return skip({ start, end, test: { path: testPath } }); 17 | } 18 | if (contents.includes('📃')) { 19 | return todo({ start, end, test: { path: testPath } }); 20 | } 21 | const errorMessage = 'Company policies require ⚔️ 🏃 in every file'; 22 | return fail({ 23 | start, 24 | end, 25 | test: { path: testPath, errorMessage, title: 'Check for ⚔️ 🏃' }, 26 | }); 27 | }; 28 | 29 | module.exports = runTest; 30 | -------------------------------------------------------------------------------- /integrationTests/skipped.test.js: -------------------------------------------------------------------------------- 1 | const runJest = require('./runJest'); 2 | 3 | it('Works when it has skipped tests', () => 4 | expect(runJest('skipped')).resolves.toMatchSnapshot()); 5 | -------------------------------------------------------------------------------- /integrationTests/slow.test.js: -------------------------------------------------------------------------------- 1 | const runJest = require('./runJest'); 2 | 3 | it('Works when it has slow tests', () => 4 | expect(runJest('slow')).resolves.toMatchSnapshot()); 5 | -------------------------------------------------------------------------------- /integrationTests/todo.test.js: -------------------------------------------------------------------------------- 1 | const runJest = require('./runJest'); 2 | 3 | it('Works when it has todo tests', () => 4 | expect(runJest('todo')).resolves.toMatchSnapshot()); 5 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /lib/createJestRunner.ts: -------------------------------------------------------------------------------- 1 | import type { TestResult } from '@jest/test-result'; 2 | import type { 3 | CallbackTestRunnerInterface, 4 | Config, 5 | OnTestFailure, 6 | OnTestStart, 7 | OnTestSuccess, 8 | Test, 9 | TestRunnerOptions, 10 | TestWatcher, 11 | } from 'jest-runner'; 12 | import { Worker, type JestWorkerFarm } from 'jest-worker'; 13 | import pLimit from 'p-limit'; 14 | import type { CreateRunnerOptions, RunTestOptions } from './types'; 15 | 16 | function determineSlowTestResult(test: Test, result: TestResult): TestResult { 17 | // See: https://github.com/facebook/jest/blob/acd7c83c8365140f4ecf44a456ff7366ffa31fa2/packages/jest-runner/src/runTest.ts#L287 18 | if (result.perfStats.runtime / 1000 > test.context.config.slowTestThreshold) { 19 | return { ...result, perfStats: { ...result.perfStats, slow: true } }; 20 | } 21 | return result; 22 | } 23 | 24 | class CancelRun extends Error { 25 | constructor(message?: string) { 26 | super(message); 27 | this.name = 'CancelRun'; 28 | } 29 | } 30 | 31 | type TestRunner = (runTestOptions: RunTestOptions) => TestResult; 32 | 33 | export default function createRunner< 34 | ExtraOptions extends Record, 35 | >( 36 | runPath: string | URL, 37 | { getExtraOptions }: CreateRunnerOptions = {}, 38 | ) { 39 | return class BaseTestRunner implements CallbackTestRunnerInterface { 40 | #globalConfig: Config.GlobalConfig; 41 | 42 | constructor(globalConfig: Config.GlobalConfig) { 43 | this.#globalConfig = globalConfig; 44 | } 45 | 46 | runTests( 47 | tests: Array, 48 | watcher: TestWatcher, 49 | onStart: OnTestStart, 50 | onResult: OnTestSuccess, 51 | onFailure: OnTestFailure, 52 | options: TestRunnerOptions, 53 | ): Promise { 54 | return options.serial 55 | ? this._createInBandTestRun( 56 | tests, 57 | watcher, 58 | onStart, 59 | onResult, 60 | onFailure, 61 | options, 62 | ) 63 | : this._createParallelTestRun( 64 | tests, 65 | watcher, 66 | onStart, 67 | onResult, 68 | onFailure, 69 | options, 70 | ); 71 | } 72 | 73 | async _createInBandTestRun( 74 | tests: Array, 75 | watcher: TestWatcher, 76 | onStart: OnTestStart, 77 | onResult: OnTestSuccess, 78 | onFailure: OnTestFailure, 79 | options: TestRunnerOptions, 80 | ): Promise { 81 | const runner: TestRunner = (await import(runPath.toString())).default; 82 | 83 | const mutex = pLimit(1); 84 | return tests.reduce( 85 | (promise, test) => 86 | mutex(() => 87 | promise 88 | .then(() => { 89 | if (watcher.isInterrupted()) { 90 | throw new CancelRun(); 91 | } 92 | 93 | return onStart(test).then(() => { 94 | const baseOptions = { 95 | config: test.context.config, 96 | globalConfig: this.#globalConfig, 97 | testPath: test.path, 98 | rawModuleMap: watcher.isWatchMode() 99 | ? test.context.moduleMap.getRawModuleMap() 100 | : null, 101 | options, 102 | extraOptions: getExtraOptions ? getExtraOptions() : {}, 103 | }; 104 | 105 | return runner(baseOptions); 106 | }); 107 | }) 108 | .then(result => determineSlowTestResult(test, result)) 109 | .then(result => onResult(test, result)) 110 | .catch(err => onFailure(test, err)), 111 | ), 112 | Promise.resolve(), 113 | ); 114 | } 115 | 116 | _createParallelTestRun( 117 | tests: Array, 118 | watcher: TestWatcher, 119 | onStart: OnTestStart, 120 | onResult: OnTestSuccess, 121 | onFailure: OnTestFailure, 122 | options: TestRunnerOptions, 123 | ): Promise { 124 | const worker = new Worker(runPath, { 125 | exposedMethods: ['default'], 126 | numWorkers: this.#globalConfig.maxWorkers, 127 | forkOptions: { stdio: 'inherit' }, 128 | }) as JestWorkerFarm<{ default: TestRunner }>; 129 | 130 | const mutex = pLimit(this.#globalConfig.maxWorkers); 131 | 132 | const runTestInWorker = (test: Test) => 133 | mutex(() => { 134 | if (watcher.isInterrupted()) { 135 | throw new CancelRun(); 136 | } 137 | 138 | return onStart(test).then(() => { 139 | const runTestOptions: RunTestOptions = { 140 | config: test.context.config, 141 | globalConfig: this.#globalConfig, 142 | testPath: test.path, 143 | rawModuleMap: watcher.isWatchMode() 144 | ? test.context.moduleMap.getRawModuleMap() 145 | : null, 146 | options, 147 | extraOptions: getExtraOptions ? getExtraOptions() : {}, 148 | }; 149 | 150 | return worker.default(runTestOptions); 151 | }); 152 | }); 153 | 154 | const onInterrupt = new Promise((_, reject) => { 155 | watcher.on('change', state => { 156 | if (state.interrupted) { 157 | reject(new CancelRun()); 158 | } 159 | }); 160 | }); 161 | 162 | const runAllTests = Promise.all( 163 | tests.map(test => 164 | runTestInWorker(test) 165 | .then(result => determineSlowTestResult(test, result)) 166 | .then(testResult => onResult(test, testResult)) 167 | .catch(error => onFailure(test, error)), 168 | ), 169 | ); 170 | 171 | const cleanup = () => { 172 | worker.end(); 173 | }; 174 | 175 | return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup); 176 | } 177 | }; 178 | } 179 | -------------------------------------------------------------------------------- /lib/fail.ts: -------------------------------------------------------------------------------- 1 | import type { TestResult } from '@jest/test-result'; 2 | import toTestResult from './toTestResult'; 3 | 4 | interface Options { 5 | start: number; 6 | end: number; 7 | test: { title: string; path: string; errorMessage?: string }; 8 | errorMessage?: string; 9 | } 10 | 11 | export default function fail(options: { 12 | start: number; 13 | end: number; 14 | test: { title: string; path: string; errorMessage: string }; 15 | }): TestResult; 16 | 17 | export default function fail(options: { 18 | start: number; 19 | end: number; 20 | test: { title: string; path: string }; 21 | errorMessage: string; 22 | }): TestResult; 23 | 24 | export default function fail({ 25 | start, 26 | end, 27 | test, 28 | errorMessage, 29 | }: Options): TestResult { 30 | // TODO: Currently the `fail` function allows 2 ways to pass an error message. 31 | // Both methods are currently in used by downstream packages. 32 | // The current behavior is to favour `errorMessage` over `test.errorMessage`. 33 | const actualErrorMessage = errorMessage || test.errorMessage; 34 | 35 | return toTestResult({ 36 | errorMessage: actualErrorMessage, 37 | stats: { 38 | failures: 1, 39 | pending: 0, 40 | passes: 0, 41 | todo: 0, 42 | start, 43 | end, 44 | }, 45 | skipped: false, 46 | tests: [ 47 | { duration: end - start, ...test, errorMessage: actualErrorMessage }, 48 | ], 49 | jestTestPath: test.path, 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default as createJestRunner } from './createJestRunner'; 2 | export { default as fail } from './fail'; 3 | export { default as pass } from './pass'; 4 | export { default as skip } from './skip'; 5 | export { default as todo } from './todo'; 6 | 7 | export type { RunTest, RunTestOptions } from './types'; 8 | -------------------------------------------------------------------------------- /lib/pass.ts: -------------------------------------------------------------------------------- 1 | import type { TestResult } from '@jest/test-result'; 2 | import toTestResult from './toTestResult'; 3 | import type { TestDetail } from './types'; 4 | 5 | interface Options { 6 | start: number; 7 | end: number; 8 | test: TestDetail; 9 | } 10 | 11 | export default function pass({ start, end, test }: Options): TestResult { 12 | return toTestResult({ 13 | stats: { 14 | failures: 0, 15 | pending: 0, 16 | passes: 1, 17 | todo: 0, 18 | start, 19 | end, 20 | }, 21 | skipped: false, 22 | tests: [{ duration: end - start, ...test }], 23 | jestTestPath: test.path, 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /lib/skip.ts: -------------------------------------------------------------------------------- 1 | import type { TestResult } from '@jest/test-result'; 2 | import toTestResult from './toTestResult'; 3 | import type { TestDetail } from './types'; 4 | 5 | interface Options { 6 | start: number; 7 | end: number; 8 | test: TestDetail; 9 | } 10 | 11 | export default function skip({ start, end, test }: Options): TestResult { 12 | return toTestResult({ 13 | stats: { 14 | failures: 0, 15 | pending: 1, 16 | passes: 0, 17 | todo: 0, 18 | start, 19 | end, 20 | }, 21 | skipped: true, 22 | tests: [{ duration: end - start, ...test }], 23 | jestTestPath: test.path, 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /lib/toTestResult.ts: -------------------------------------------------------------------------------- 1 | import type { TestResult } from '@jest/test-result'; 2 | 3 | interface Options { 4 | stats: { 5 | failures: number; 6 | passes: number; 7 | pending: number; 8 | todo: number; 9 | start: number; 10 | end: number; 11 | }; 12 | skipped: boolean; 13 | errorMessage?: string | null; 14 | tests: Array<{ 15 | duration?: number | null; 16 | errorMessage?: string; 17 | testPath?: string; 18 | title?: string; 19 | }>; 20 | jestTestPath: string; 21 | } 22 | 23 | function getPerfStats({ stats }: Options): TestResult['perfStats'] { 24 | const start = new Date(stats.start).getTime(); 25 | const end = new Date(stats.end).getTime(); 26 | const runtime = end - start; 27 | // Note: this flag is set in 'lib/createJestRunner.ts' 28 | const slow = false; 29 | return { start, end, runtime, slow }; 30 | } 31 | 32 | function getSnapshot(): TestResult['snapshot'] { 33 | return { 34 | added: 0, 35 | fileDeleted: false, 36 | matched: 0, 37 | unchecked: 0, 38 | uncheckedKeys: [], 39 | unmatched: 0, 40 | updated: 0, 41 | }; 42 | } 43 | 44 | function getTestResults({ 45 | errorMessage, 46 | tests, 47 | jestTestPath, 48 | }: Options): TestResult['testResults'] { 49 | return tests.map(test => { 50 | const actualErrorMessage = errorMessage || test.errorMessage; 51 | 52 | return { 53 | ancestorTitles: [], 54 | duration: test.duration, 55 | failureDetails: [], 56 | failureMessages: actualErrorMessage ? [actualErrorMessage] : [], 57 | fullName: jestTestPath || test.testPath || '', 58 | numPassingAsserts: test.errorMessage ? 1 : 0, 59 | status: test.errorMessage ? 'failed' : 'passed', 60 | title: test.title || '', 61 | }; 62 | }); 63 | } 64 | 65 | export default function toTestResult(options: Options): TestResult { 66 | const { stats, skipped, errorMessage, jestTestPath } = options; 67 | return { 68 | failureMessage: errorMessage, 69 | leaks: false, 70 | numFailingTests: stats.failures, 71 | numPassingTests: stats.passes, 72 | numPendingTests: stats.pending, 73 | numTodoTests: stats.todo, 74 | openHandles: [], 75 | perfStats: getPerfStats(options), 76 | skipped, 77 | snapshot: getSnapshot(), 78 | testFilePath: jestTestPath, 79 | testResults: getTestResults(options), 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /lib/todo.ts: -------------------------------------------------------------------------------- 1 | import type { TestResult } from '@jest/test-result'; 2 | import toTestResult from './toTestResult'; 3 | import type { TestDetail } from './types'; 4 | 5 | interface Options { 6 | start: number; 7 | end: number; 8 | test: TestDetail; 9 | } 10 | 11 | export default function todo({ start, end, test }: Options): TestResult { 12 | return toTestResult({ 13 | stats: { 14 | failures: 0, 15 | pending: 0, 16 | passes: 0, 17 | todo: 1, 18 | start, 19 | end, 20 | }, 21 | skipped: false, 22 | tests: [{ duration: end - start, ...test }], 23 | jestTestPath: test.path, 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /lib/types.ts: -------------------------------------------------------------------------------- 1 | import type { TestContext, TestResult } from '@jest/test-result'; 2 | import type { Config, TestRunnerOptions } from 'jest-runner'; 3 | 4 | export interface CreateRunnerOptions< 5 | ExtraOptions extends Record, 6 | > { 7 | getExtraOptions?: () => ExtraOptions; 8 | } 9 | 10 | export type RunTestOptions< 11 | ExtraOptions extends Record = Record, 12 | > = { 13 | config: Config.ProjectConfig; 14 | extraOptions: ExtraOptions; 15 | globalConfig: Config.GlobalConfig; 16 | rawModuleMap: ReturnType | null; 17 | options: TestRunnerOptions; 18 | testPath: string; 19 | }; 20 | 21 | export type RunTest< 22 | ExtraOptions extends Record = Record, 23 | > = (options: RunTestOptions) => TestResult | Promise; 24 | 25 | export interface TestDetail { 26 | title: string; 27 | path: string; 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-jest-runner", 3 | "version": "0.12.3", 4 | "main": "build/index.js", 5 | "types": "build/index.d.ts", 6 | "exports": { 7 | ".": { 8 | "types": "./build/index.d.ts", 9 | "default": "./build/index.js" 10 | }, 11 | "./package.json": "./package.json", 12 | "./generator/index.js": "./generator/index.js" 13 | }, 14 | "author": "Rogelio Guzman ", 15 | "contributors": [ 16 | { 17 | "name": "Lok Shun Hung", 18 | "url": "https://github.com/lokshunhung" 19 | } 20 | ], 21 | "description": "A simple way of creating a Jest runner", 22 | "license": "MIT", 23 | "repository": "https://github.com/jest-community/create-jest-runner.git", 24 | "homepage": "https://github.com/jest-community/create-jest-runner", 25 | "files": [ 26 | "build/", 27 | "generator/" 28 | ], 29 | "scripts": { 30 | "test": "jest --no-color", 31 | "lint": "eslint .", 32 | "prettier:run": "prettier '*.md' '.github/**' '*.json' '**/package.json' '.vscode/*.json' 'generator/fixtures/*'", 33 | "prettier:check": "yarn prettier:run --check", 34 | "prettier:write": "yarn prettier:run --write", 35 | "watch": "yarn build --watch", 36 | "build": "babel lib --ignore '**/*.test.js,integration' --out-dir build --extensions '.ts'", 37 | "build-types": "tsc", 38 | "prepare": "yarn build && yarn build-types" 39 | }, 40 | "dependencies": { 41 | "chalk": "^4.1.0", 42 | "jest-worker": "^29.5.0", 43 | "p-limit": "^3.1.0" 44 | }, 45 | "devDependencies": { 46 | "@babel/cli": "^7.0.0", 47 | "@babel/core": "^7.0.0", 48 | "@babel/preset-env": "^7.0.0", 49 | "@babel/preset-typescript": "^7.0.0", 50 | "@jest/test-result": "^29.0.0", 51 | "@tsconfig/node14": "^14.0.0", 52 | "@types/node": "^14.18.23", 53 | "@typescript-eslint/eslint-plugin": "^6.0.0", 54 | "@typescript-eslint/parser": "^6.0.0", 55 | "babel-jest": "^29.0.0", 56 | "eslint": "^8.10.0", 57 | "eslint-config-airbnb-base": "^15.0.0", 58 | "eslint-config-prettier": "^10.0.0", 59 | "eslint-plugin-import": "^2.7.0", 60 | "eslint-plugin-jest": "^27.0.0", 61 | "eslint-plugin-prettier": "^4.0.0", 62 | "execa": "^5.0.0", 63 | "jest": "^29.0.0", 64 | "jest-runner": "^29.0.0", 65 | "prettier": "^2.0.5", 66 | "semver": "^7.3.8", 67 | "strip-ansi": "^6.0.0", 68 | "typescript": "^5.0.0" 69 | }, 70 | "peerDependencies": { 71 | "@jest/test-result": "^28.0.0 || ^29.0.0", 72 | "jest-runner": "^28.0.0 || ^29.0.0" 73 | }, 74 | "peerDependenciesMeta": { 75 | "@jest/test-result": { 76 | "optional": true 77 | }, 78 | "jest-runner": { 79 | "optional": true 80 | } 81 | }, 82 | "bin": "./generator/index.js", 83 | "prettier": { 84 | "arrowParens": "avoid", 85 | "singleQuote": true, 86 | "trailingComma": "all" 87 | }, 88 | "resolutions": { 89 | "@types/node@*": "^14.18.23" 90 | }, 91 | "engines": { 92 | "node": "^14.15.0 || ^16.10.0 || >=18.0.0" 93 | }, 94 | "packageManager": "yarn@3.8.7" 95 | } 96 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node14/tsconfig.json", 3 | "compilerOptions": { 4 | /* Basic Options */ 5 | // "allowJs": true, 6 | // "checkJs": true, 7 | "declaration": true, 8 | "emitDeclarationOnly": true, 9 | "outDir": "./build/", 10 | "noErrorTruncation": true, 11 | "isolatedModules": true, 12 | 13 | "stripInternal": true, 14 | "esModuleInterop": true, 15 | "skipLibCheck": false, 16 | 17 | /* Additional Checks */ 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noImplicitOverride": true, 21 | "noImplicitReturns": true, 22 | "noFallthroughCasesInSwitch": true, 23 | 24 | /* Advanced Options */ 25 | "forceConsistentCasingInFileNames": true 26 | }, 27 | "include": ["./lib/"], 28 | "exclude": ["./build/"] 29 | } 30 | --------------------------------------------------------------------------------