diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4d795b96..17591598 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: validate before release run: | diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 5eb7f444..cd7d7f67 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -8,13 +8,16 @@ jobs: strategy: matrix: - # Test with Node.js v12 (LTS), v14 (LTS), and v16 (latest) - node: [12.x, 14.x, 15.x, 16.x] + # Test with Node.js v14 (LTS), v16 (LTS), and v18 + node: [14.x, 16.x, 18.x] steps: - - uses: actions/checkout@v1 + - name: 🛑 Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.9.1 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} @@ -35,11 +38,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: - node-version: '14.x' + node-version: '18.x' registry-url: 'https://registry.npmjs.org' - name: install dependencies diff --git a/README.md b/README.md index d3e67e95..f2ef2211 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,20 @@ module.exports = { > configuring things to make it less magical and more straightforward. Extending > can take place on your terms. I think this is actually a great way to do this. +### ES Module Support with jest (`cod-scripts test`) + +As of this writing, jest esmodule support is still a [WIP](https://github.com/facebook/jest/issues/12270). If you're testing a nodejs esmodule, you need to pass +the `--experimental-vm-modules` flag to node. For example: + +**package.json** +```json +"scripts": { + "test": "NODE_OPTIONS=--experimental-vm-modules cod-scripts test" +} +``` + +See: + ### TypeScript Support If the `tsconfig.json`-file is present in the project root directory and diff --git a/package.json b/package.json index 2021d1bf..475656aa 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,8 @@ "version": "0.0.0-semantically-released", "description": "CLI for common scripts for my projects", "engines": { - "node": ">=12.13.0", - "npm": ">=6", - "yarn": ">=1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" }, "bin": { "cod-scripts": "dist/index.js" @@ -34,66 +33,72 @@ "author": "Chris O'Donnell (http://codfish.io/)", "license": "MIT", "dependencies": { - "@babel/cli": "^7.14.3", - "@babel/core": "^7.14.3", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-transform-modules-commonjs": "^7.14.0", - "@babel/plugin-transform-runtime": "^7.14.3", - "@babel/preset-env": "^7.14.4", - "@babel/preset-react": "^7.13.13", - "@babel/preset-typescript": "^7.13.0", - "@babel/runtime": "^7.14.0", - "@commitlint/cli": "^13.1.0", - "@commitlint/config-conventional": "^13.1.0", - "@rollup/plugin-babel": "^5.3.0", - "@rollup/plugin-commonjs": "^19.0.0", + "@babel/cli": "^7.17.6", + "@babel/core": "^7.17.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.17.7", + "@babel/plugin-transform-runtime": "^7.17.0", + "@babel/preset-env": "^7.16.11", + "@babel/preset-react": "^7.16.7", + "@babel/preset-typescript": "^7.16.7", + "@babel/runtime": "^7.17.8", + "@commitlint/cli": "^17.0.3", + "@commitlint/config-conventional": "^17.0.3", + "@rollup/plugin-babel": "^5.3.1", + "@rollup/plugin-commonjs": "^21.0.3", "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.0", - "@rollup/plugin-replace": "^2.4.2", - "@types/jest": "^26.0.23", + "@rollup/plugin-node-resolve": "^13.1.3", + "@rollup/plugin-replace": "^4.0.0", + "@types/jest": "^27.4.1", "arrify": "^2.0.1", - "babel-jest": "^27.0.2", + "babel-jest": "^27.5.1", "babel-plugin-macros": "^3.1.0", "babel-plugin-minify-dead-code-elimination": "^0.5.1", "babel-plugin-module-resolver": "^4.0.0", "babel-plugin-transform-inline-environment-variables": "^0.4.3", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", - "browserslist": "^4.16.6", + "browserslist": "^4.20.2", "builtin-modules": "^3.2.0", - "chalk": "^4.1.1", - "concurrently": "^6.2.0", - "cosmiconfig": "^7.0.0", + "chalk": "^5.0.1", + "concurrently": "^7.1.0", + "cosmiconfig": "^7.0.1", "cpy": "^8.1.2", "cross-env": "^7.0.3", "cross-spawn": "^7.0.3", - "doctoc": "^2.0.0", - "eslint": "^7.28.0", - "eslint-config-codfish": "^10.3.0", - "glob": "^7.1.7", - "husky": "^7.0.1", - "is-ci": "^3.0.0", - "jest": "^27.0.4", + "doctoc": "^2.1.0", + "eslint": "^8.12.0", + "eslint-config-codfish": "^11.1.0", + "eslint-config-kentcdodds": "^20.2.0", + "glob": "^8.0.3", + "husky": "^8.0.1", + "is-ci": "^3.0.1", + "jest": "^27.5.1", "jest-serializer-path": "^0.1.15", "jest-snapshot-serializer-raw": "^1.2.0", - "jest-watch-typeahead": "^0.6.4", - "lint-staged": "^11.0.0", + "jest-watch-typeahead": "^1.0.0", + "lint-staged": "^13.0.3", "lodash.camelcase": "^4.3.0", "lodash.has": "^4.5.2", "lodash.omit": "^4.5.0", "mkdirp": "^1.0.4", - "prettier": "^2.3.1", - "react-app-polyfill": "^2.0.0", + "prettier": "^2.7.1", + "react-app-polyfill": "^3.0.0", "read-pkg-up": "^7.0.1", - "resolve": "^1.20.0", + "resolve": "^1.22.0", "rimraf": "^3.0.2", - "rollup": "^2.51.0", + "rollup": "^2.70.1", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-size-snapshot": "^0.12.0", "rollup-plugin-terser": "^7.0.2", "semver": "^7.3.5", "which": "^2.0.2", - "yargs-parser": "^20.2.7" + "yargs-parser": "^21.0.1" + }, + "devDependencies": { + "jest-in-case": "^1.0.2", + "slash": "^3.0.0", + "typescript": "^4.3.2" }, "eslintConfig": { "extends": [ @@ -152,10 +157,5 @@ "bugs": { "url": "https://github.com/codfish/cod-scripts/issues" }, - "homepage": "https://github.com/codfish/cod-scripts#readme", - "devDependencies": { - "jest-in-case": "^1.0.2", - "slash": "^3.0.0", - "typescript": "^4.3.2" - } + "homepage": "https://github.com/codfish/cod-scripts#readme" } diff --git a/src/__tests__/__snapshots__/index.js.snap b/src/__tests__/__snapshots__/index.js.snap index e11a482a..5342be99 100644 --- a/src/__tests__/__snapshots__/index.js.snap +++ b/src/__tests__/__snapshots__/index.js.snap @@ -1,12 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`format calls node with the script path and args 1`] = `node /src/scripts/test.js --no-watch`; +exports[`format calls node with the script path and args including inspect-brk argument: format script 1`] = `node --inspect-brk=3080 /src/scripts/test.js --no-watch`; -exports[`format calls node with the script path and args including inspect-brk argument 1`] = `node --inspect-brk=3080 /src/scripts/test.js --no-watch`; +exports[`format calls node with the script path and args: format script 1`] = `node /src/scripts/test.js --no-watch`; -exports[`format does not log for other signals 1`] = `Array []`; +exports[`format does not log for other signals: format signal 1`] = `Array []`; -exports[`format logs for SIGKILL signal 1`] = ` +exports[`format logs for SIGKILL signal: format signal 1`] = ` Array [ Array [ The script "lint" failed because the process exited too early. This probably means the system ran out of memory or someone called \`kill -9\` on the process., @@ -14,7 +14,7 @@ Array [ ] `; -exports[`format logs for SIGTERM signal 1`] = ` +exports[`format logs for SIGTERM signal: format signal 1`] = ` Array [ Array [ The script "build" failed because the process exited too early. Someone might have called \`kill\` or \`killall\`, or the system could be shutting down., @@ -22,7 +22,7 @@ Array [ ] `; -exports[`format logs help with no args 1`] = ` +exports[`format logs help with no args: format snapshotLog 1`] = ` Array [ Array [ @@ -47,4 +47,4 @@ May the force be with you. ] `; -exports[`format throws unknown script 1`] = `Unknown script "unknown-script".`; +exports[`format throws unknown script: format error 1`] = `Unknown script "unknown-script".`; diff --git a/src/__tests__/index.js b/src/__tests__/index.js index 454525f9..5a7f0190 100644 --- a/src/__tests__/index.js +++ b/src/__tests__/index.js @@ -28,20 +28,22 @@ cases( } require('..') if (snapshotLog) { - expect(console.log.mock.calls).toMatchSnapshot() + expect(console.log.mock.calls).toMatchSnapshot('format snapshotLog') } else if (signal) { expect(process.exit).toHaveBeenCalledTimes(1) expect(process.exit).toHaveBeenCalledWith(1) - expect(console.log.mock.calls).toMatchSnapshot() + expect(console.log.mock.calls).toMatchSnapshot('format signal') } else { expect(crossSpawnSyncMock).toHaveBeenCalledTimes(1) const [firstCall] = crossSpawnSyncMock.mock.calls const [script, calledArgs] = firstCall - expect([script, ...calledArgs].join(' ')).toMatchSnapshot() + expect([script, ...calledArgs].join(' ')).toMatchSnapshot( + 'format script', + ) } } catch (error) { if (throws) { - expect(error.message).toMatchSnapshot() + expect(error.message).toMatchSnapshot('format error') } else { throw error } diff --git a/src/config/jest.config.js b/src/config/jest.config.js index 5a340f7a..73190533 100644 --- a/src/config/jest.config.js +++ b/src/config/jest.config.js @@ -1,5 +1,12 @@ const path = require('path') -const {ifAnyDep, hasFile, ifFile, hasPkgProp, fromRoot} = require('../utils') +const { + ifAnyDep, + hasFile, + ifFile, + hasPkgProp, + fromRoot, + isEsm, +} = require('../utils') const here = p => path.join(__dirname, p) @@ -16,16 +23,15 @@ const ignores = [ ] const jestConfig = { - roots: [fromRoot(hasFile('src') ? 'src' : '')], - testEnvironment: ifAnyDep(['webpack', 'rollup', 'react'], 'jsdom', 'node'), + roots: [hasFile('src') ? '/src' : ''], + testEnvironment: ifAnyDep( + ['webpack', 'rollup', 'react', 'preact'], + 'jsdom', + 'node', + ), testURL: 'http://localhost', moduleFileExtensions: ['js', 'jsx', 'json', 'ts', 'tsx'], - moduleDirectories: [ - 'node_modules', - fromRoot('src'), - 'shared', - fromRoot('tests'), - ], + modulePaths: ['/src', 'shared', '/tests'], collectCoverageFrom: ['src/**/*.+(js|jsx|ts|tsx)'], testMatch: [ '**/__tests__/**/*.+(js|jsx|ts|tsx)', @@ -75,6 +81,16 @@ if (useBuiltInBabelConfig) { } } +// make esmodules work +// https://jestjs.io/docs/ecmascript-modules +if (isEsm) { + // see https://github.com/chalk/chalk/issues/532#issuecomment-1062018375 + jestConfig.moduleNameMapper = { + '#(.*)': '/node_modules/$1', + } + jestConfig.transform = {} +} + if (jestConfig.testEnvironment === 'jsdom') { jestConfig.setupFiles = [require.resolve('react-app-polyfill/jsdom')] } diff --git a/src/config/prettierrc.js b/src/config/prettierrc.js index 2dff51a0..69d45fab 100644 --- a/src/config/prettierrc.js +++ b/src/config/prettierrc.js @@ -14,7 +14,7 @@ module.exports = { requirePragma: false, singleQuote: true, trailingComma: 'all', - jsxBracketSameLine: false, + bracketSameLine: false, proseWrap: 'always', vueIndentScriptAndStyle: false, } diff --git a/src/scripts/__tests__/__snapshots__/pre-commit.js.snap b/src/scripts/__tests__/__snapshots__/pre-commit.js.snap index 9f717644..4d6fbf72 100644 --- a/src/scripts/__tests__/__snapshots__/pre-commit.js.snap +++ b/src/scripts/__tests__/__snapshots__/pre-commit.js.snap @@ -1,25 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`pre-commit calls lint-staged CLI with default args 1`] = `lint-staged --config ./src/config/lintstagedrc.js`; +exports[`pre-commit calls lint-staged CLI with default args: pre-commit scriptOne 1`] = `lint-staged --config ./src/config/lintstagedrc.js`; -exports[`pre-commit calls lint-staged CLI with default args 2`] = `npm run validate`; +exports[`pre-commit calls lint-staged CLI with default args: pre-commit scriptTwo 1`] = `npm run validate`; -exports[`pre-commit does not use built-in config with .lintstagedrc file 1`] = `lint-staged`; +exports[`pre-commit does not use built-in config with .lintstagedrc file: pre-commit scriptOne 1`] = `lint-staged`; -exports[`pre-commit does not use built-in config with .lintstagedrc file 2`] = `npm run validate`; +exports[`pre-commit does not use built-in config with .lintstagedrc file: pre-commit scriptTwo 1`] = `npm run validate`; -exports[`pre-commit does not use built-in config with --config 1`] = `lint-staged --config ./custom-config.js`; +exports[`pre-commit does not use built-in config with --config: pre-commit scriptOne 1`] = `lint-staged --config ./custom-config.js`; -exports[`pre-commit does not use built-in config with --config 2`] = `npm run validate`; +exports[`pre-commit does not use built-in config with --config: pre-commit scriptTwo 1`] = `npm run validate`; -exports[`pre-commit does not use built-in config with lint-staged pkg prop 1`] = `lint-staged`; +exports[`pre-commit does not use built-in config with lint-staged pkg prop: pre-commit scriptOne 1`] = `lint-staged`; -exports[`pre-commit does not use built-in config with lint-staged pkg prop 2`] = `npm run validate`; +exports[`pre-commit does not use built-in config with lint-staged pkg prop: pre-commit scriptTwo 1`] = `npm run validate`; -exports[`pre-commit does not use built-in config with lint-staged.config.js file 1`] = `lint-staged`; +exports[`pre-commit does not use built-in config with lint-staged.config.js file: pre-commit scriptOne 1`] = `lint-staged`; -exports[`pre-commit does not use built-in config with lint-staged.config.js file 2`] = `npm run validate`; +exports[`pre-commit does not use built-in config with lint-staged.config.js file: pre-commit scriptTwo 1`] = `npm run validate`; -exports[`pre-commit forwards args 1`] = `lint-staged --config ./src/config/lintstagedrc.js --verbose`; +exports[`pre-commit forwards args: pre-commit scriptOne 1`] = `lint-staged --config ./src/config/lintstagedrc.js --verbose`; -exports[`pre-commit forwards args 2`] = `npm run validate`; +exports[`pre-commit forwards args: pre-commit scriptTwo 1`] = `npm run validate`; diff --git a/src/scripts/__tests__/format.js b/src/scripts/__tests__/format.js index bab68a53..40322e5e 100644 --- a/src/scripts/__tests__/format.js +++ b/src/scripts/__tests__/format.js @@ -1,5 +1,5 @@ +/* eslint-disable jest/prefer-snapshot-hint */ import cases from 'jest-in-case' - import {winPathSerializer} from './helpers/serializers' expect.addSnapshotSerializer(winPathSerializer) diff --git a/src/scripts/__tests__/pre-commit.js b/src/scripts/__tests__/pre-commit.js index 76bf605e..e59718c8 100644 --- a/src/scripts/__tests__/pre-commit.js +++ b/src/scripts/__tests__/pre-commit.js @@ -31,9 +31,13 @@ cases( expect(crossSpawnSyncMock).toHaveBeenCalledTimes(2) const [firstCall, secondCall] = crossSpawnSyncMock.mock.calls const [scriptOne, calledArgsOne] = firstCall - expect([scriptOne, ...calledArgsOne].join(' ')).toMatchSnapshot() + expect([scriptOne, ...calledArgsOne].join(' ')).toMatchSnapshot( + 'pre-commit scriptOne', + ) const [scriptTwo, calledArgsTwo] = secondCall - expect([scriptTwo, ...calledArgsTwo].join(' ')).toMatchSnapshot() + expect([scriptTwo, ...calledArgsTwo].join(' ')).toMatchSnapshot( + 'pre-commit scriptTwo', + ) } catch (error) { throw error } finally { diff --git a/src/utils.js b/src/utils.js index f95a8234..aa3daf26 100644 --- a/src/utils.js +++ b/src/utils.js @@ -15,6 +15,7 @@ const {packageJson: pkg, path: pkgPath} = readPkgUp.sync({ cwd: fs.realpathSync(process.cwd()), }) const appDirectory = path.dirname(pkgPath) +const isEsm = pkg.type === 'module' function resolveBin(modName, {executable = modName, cwd = process.cwd()} = {}) { let pathFromWhich @@ -248,4 +249,5 @@ module.exports = { generateTypeDefs, getRollupInputs, getRollupOutput, + isEsm, }