Skip to content

Commit

Permalink
Migrate type tests to Vitest (#4731)
Browse files Browse the repository at this point in the history
Co-authored-by: Tim Dorr <[email protected]>
  • Loading branch information
aryaemami59 and timdorr authored Aug 16, 2024
1 parent d63640f commit b59da78
Show file tree
Hide file tree
Showing 35 changed files with 3,775 additions and 4,782 deletions.
17 changes: 0 additions & 17 deletions .babelrc.cjs

This file was deleted.

17 changes: 13 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ jobs:
- name: Lint
run: yarn lint

- name: Run test suite
run: yarn test

- name: Build
run: yarn build

Expand Down Expand Up @@ -90,9 +93,12 @@ jobs:
- name: Install build artifact
run: yarn add ./package.tgz

- run: sed -i -e /@remap-prod-remove-line/d ./tsconfig.json ./vitest.config.mts ./test/tsconfig.json ./test/typescript/tsconfig.json
- name: Erase path aliases
run: sed -i -e /@remap-prod-remove-line/d tsconfig.base.json

- name: Run tests, against dist
env:
TEST_DIST: true
run: yarn test

test-types:
Expand Down Expand Up @@ -129,12 +135,15 @@ jobs:
- name: Install build artifact
run: yarn add ./package.tgz

- name: Erase path aliases
run: sed -i -e /@remap-prod-remove-line/d tsconfig.base.json

- name: Test types
env:
TEST_DIST: true
run: |
yarn tsc --version
yarn check-types
yarn test:typecheck
yarn test:types
yarn type-tests
are-the-types-wrong:
name: Check package config with are-the-types-wrong
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ website/translated_docs
website/build/
website/node_modules
website/i18n/*

tsconfig.vitest-temp.json

.vscode
15 changes: 7 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,20 @@
"format": "prettier --write \"{src,test}/**/*.{js,ts}\" \"**/*.md\"",
"format:check": "prettier --list-different \"{src,test}/**/*.{js,ts}\" \"**/*.md\"",
"lint": "eslint --ext js,ts src test",
"check-types": "tsc --noEmit && echo \"Types compiled\"",
"test": "vitest --run",
"test:types": "tsc -p test/typescript && echo \"Typetests passed\"",
"test": "vitest --run --typecheck",
"type-tests": "tsc -p tsconfig.test.json --noEmit",
"test:watch": "vitest --watch",
"test:cov": "vitest --coverage",
"test:typecheck": "tsc -p test && echo \"Types passed\"",
"build": "tsup",
"prepublishOnly": "yarn clean && yarn check-types && yarn format:check && yarn lint && yarn test",
"build": "yarn clean && tsup",
"prepublishOnly": "yarn clean && yarn format:check && yarn lint && yarn test",
"prepack": "yarn build",
"examples:lint": "eslint --ext js,ts examples",
"examples:test": "cross-env CI=true babel-node examples/testAll.js",
"tsc": "tsc"
},
"devDependencies": {
"@babel/core": "^7.24.3",
"@types/babel__core": "^7.20.5",
"@types/babel__helper-module-imports": "^7.18.3",
"@types/node": "^20.11.30",
"@typescript-eslint/eslint-plugin": "^7.3.1",
"@typescript-eslint/parser": "^7.3.1",
Expand All @@ -76,7 +75,7 @@
"rxjs": "^7.8.1",
"tsup": "8.0.2",
"typescript": "^5.5.4",
"vitest": "^1.4.0"
"vitest": "^2.0.5"
},
"resolutions": {
"@typescript-eslint/eslint-plugin": "7.3.1",
Expand Down
79 changes: 0 additions & 79 deletions rollup.config.js

This file was deleted.

79 changes: 57 additions & 22 deletions scripts/mangleErrors.cjs → scripts/mangleErrors.mts
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
const fs = require('fs')
const helperModuleImports = require('@babel/helper-module-imports')
import type { Node, PluginObj, PluginPass } from '@babel/core'
import * as helperModuleImports from '@babel/helper-module-imports'
import * as fs from 'node:fs'

type Babel = typeof import('@babel/core')

/**
* Converts an AST type into a javascript string so that it can be added to the error message lookup.
* Represents the options for the {@linkcode mangleErrorsPlugin}.
*
* @internal
*/
export interface MangleErrorsPluginOptions {
/**
* Whether to minify the error messages or not.
* If `true`, the error messages will be replaced with an index
* that maps object lookup.
*/
minify: boolean
}

/**
* Converts an AST type into a JavaScript string so that it can be added to the error message lookup.
*
* Adapted from React (https://github.com/facebook/react/blob/master/scripts/shared/evalToString.js) with some
* adjustments
* adjustments.
*/
const evalToString = ast => {
const evalToString = (
ast: Node | { type: 'Literal'; value: string }
): string => {
switch (ast.type) {
case 'StringLiteral':
case 'Literal': // ESLint
Expand All @@ -31,14 +50,14 @@ const evalToString = ast => {
}

/**
* Takes a `throw new error` statement and transforms it depending on the minify argument. Either option results in a
* smaller bundle size in production for consumers.
* Transforms a `throw new Error` statement based on the `minify` argument, resulting in a smaller bundle size
* for consumers in production.
*
* If minify is enabled, we'll replace the error message with just an index that maps to an arrow object lookup.
* If `minify` is enabled, the error message will be replaced with an index that maps to an object lookup.
*
* If minify is disabled, we'll add in a conditional statement to check the process.env.NODE_ENV which will output a
* an error number index in production or the actual error message in development. This allows consumers using webpack
* or another build tool to have these messages in development but have just the error index in production.
* If `minify` is disabled, a conditional statement will be added to check `process.env.NODE_ENV`, which will output
* an error number index in production or the actual error message in development. This allows consumers using Webpack
* or another build tool to have these messages in development but only the error index in production.
*
* E.g.
* Before:
Expand All @@ -49,30 +68,40 @@ const evalToString = ast => {
* throw new Error(0);
* throw new Error(1);
*
* After: (without minify):
* throw new Error(node.process.NODE_ENV === 'production' ? 0 : "This is my error message.");
* throw new Error(node.process.NODE_ENV === 'production' ? 1 : "This is a second error message.");
* After (without minify):
* throw new Error(process.env.NODE_ENV === 'production' ? 0 : "This is my error message.");
* throw new Error(process.env.NODE_ENV === 'production' ? 1 : "This is a second error message.");
*/
module.exports = babel => {
export const mangleErrorsPlugin = (
babel: Babel,
options: MangleErrorsPluginOptions
): PluginObj<PluginPass & MangleErrorsPluginOptions> => {
const t = babel.types
// When the plugin starts up, we'll load in the existing file. This allows us to continually add to it so that the
// indexes do not change between builds.
let errorsFiles = ''
if (fs.existsSync('errors.json')) {
errorsFiles = fs.readFileSync('errors.json').toString()
}
let errors = Object.values(JSON.parse(errorsFiles || '{}'))
const errors = Object.values(JSON.parse(errorsFiles || '{}'))
// This variable allows us to skip writing back to the file if the errors array hasn't changed
let changeInArray = false

return {
name: 'mangle-errors-plugin',
pre: () => {
changeInArray = false
},
visitor: {
ThrowStatement(path, file) {
ThrowStatement(path) {
if (
!('arguments' in path.node.argument) ||
!t.isNewExpression(path.node.argument)
) {
return
}
const args = path.node.argument.arguments
const minify = file.opts.minify
const { minify } = options

if (args && args[0]) {
// Skip running this logic when certain types come up:
Expand All @@ -82,11 +111,15 @@ module.exports = babel => {
path.node.argument.arguments[0].type === 'Identifier' ||
path.node.argument.arguments[0].type === 'NumericLiteral' ||
path.node.argument.arguments[0].type === 'ConditionalExpression' ||
path.node.argument.arguments[0].type === 'CallExpression'
path.node.argument.arguments[0].type === 'CallExpression' ||
!t.isExpression(path.node.argument.arguments[0]) ||
!t.isIdentifier(path.node.argument.callee)
) {
return
}

const errorName = path.node.argument.callee.name

const errorMsgLiteral = evalToString(path.node.argument.arguments[0])

if (errorMsgLiteral.includes('Super expression')) {
Expand All @@ -106,7 +139,7 @@ module.exports = babel => {
const formatProdErrorMessageIdentifier = helperModuleImports.addNamed(
path,
'formatProdErrorMessage',
'src/utils/formatProdErrorMessage',
'@internal/utils/formatProdErrorMessage',
{ nameHint: 'formatProdErrorMessage' }
)

Expand All @@ -119,13 +152,13 @@ module.exports = babel => {
if (minify) {
path.replaceWith(
t.throwStatement(
t.newExpression(t.identifier('Error'), [prodMessage])
t.newExpression(t.identifier(errorName), [prodMessage])
)
)
} else {
path.replaceWith(
t.throwStatement(
t.newExpression(t.identifier('Error'), [
t.newExpression(t.identifier(errorName), [
t.conditionalExpression(
t.binaryExpression(
'===',
Expand All @@ -150,3 +183,5 @@ module.exports = babel => {
}
}
}

export default mangleErrorsPlugin
7 changes: 7 additions & 0 deletions src/createStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ import ActionTypes from './utils/actionTypes'
import isPlainObject from './utils/isPlainObject'
import { kindOf } from './utils/kindOf'

/**
* Prevents TypeScript from inferring a generic type parameter.
*
* @template T - The type to prevent inference for.
*
* @internal
*/
type NoInfer<T> = [T][T extends any ? 0 : never]

/**
Expand Down
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import __DO_NOT_USE__ActionTypes from './utils/actionTypes'

// types
// store
export {
export type {
Dispatch,
Unsubscribe,
Observable,
Expand All @@ -21,7 +21,7 @@ export {
StoreEnhancerStoreCreator
} from './types/store'
// reducers
export {
export type {
Reducer,
ReducersMapObject,
StateFromReducersMapObject,
Expand All @@ -31,11 +31,11 @@ export {
PreloadedStateShapeFromReducersMapObject
} from './types/reducers'
// action creators
export { ActionCreator, ActionCreatorsMapObject } from './types/actions'
export type { ActionCreator, ActionCreatorsMapObject } from './types/actions'
// middleware
export { MiddlewareAPI, Middleware } from './types/middleware'
export type { MiddlewareAPI, Middleware } from './types/middleware'
// actions
export { Action, UnknownAction, AnyAction } from './types/actions'
export type { Action, UnknownAction, AnyAction } from './types/actions'

export {
createStore,
Expand Down
Loading

0 comments on commit b59da78

Please sign in to comment.