Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: use Vitest for unit testing, clean regex bug (#8040)
  • Loading branch information
antfu committed May 6, 2022
1 parent c7eeb8d commit 63cd53d
Show file tree
Hide file tree
Showing 26 changed files with 160 additions and 15 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.cjs
Expand Up @@ -63,7 +63,7 @@ module.exports = defineConfig({
'node/no-extraneous-import': [
'error',
{
allowModules: ['vite', 'less', 'sass']
allowModules: ['vite', 'less', 'sass', 'vitest']
}
],
'node/no-extraneous-require': [
Expand Down Expand Up @@ -103,7 +103,7 @@ module.exports = defineConfig({
}
},
{
files: ['packages/vite/types/**'],
files: ['packages/vite/types/**', '*.spec.ts'],
rules: {
'node/no-extraneous-import': 'off'
}
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -66,6 +66,9 @@ jobs:
- name: Build plugin-react
run: pnpm run build-plugin-react

- name: Test unit
run: pnpm run test-unit

- name: Test serve
run: pnpm run test-serve -- --runInBand

Expand Down
14 changes: 12 additions & 2 deletions CONTRIBUTING.md
Expand Up @@ -67,13 +67,15 @@ And re-run `pnpm install` to link the package.

## Running Tests

### Integration Tests

Each package under `packages/playground/` contains a `__tests__` directory. The tests are run using [Jest](https://jestjs.io/) + [Playwright](https://playwright.dev/) with custom integrations to make writing tests simple. The detailed setup is inside `jest.config.js` and `scripts/jest*` files.

Before running the tests, make sure that [Vite has been built](#repo-setup). On Windows, you may want to [activate Developer Mode](https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development) to solve [issues with symlink creation for non-admins](https://github.com/vitejs/vite/issues/7390). Also you may want to [set git `core.symlinks` to `true` to solve issues with symlinks in git](https://github.com/vitejs/vite/issues/5242).

Each test can be run under either dev server mode or build mode.
Each integration test can be run under either dev server mode or build mode.

- `pnpm test` by default runs every test in both serve and build mode.
- `pnpm test` by default runs every integration test in both serve and build mode, and also unit tests.

- `pnpm run test-serve` runs tests only under serve mode. This is just calling `jest` so you can pass any Jest flags to this command. Since Jest will attempt to run tests in parallel, if your machine has many cores this may cause flaky test failures with multiple Playwright instances running at the same time. You can force the tests to run in series with `pnpm run test-serve -- --runInBand`.

Expand All @@ -83,6 +85,14 @@ Each test can be run under either dev server mode or build mode.

Note package matching is not available for the `pnpm test` script, which always runs all tests.

### Unit Tests

Other than tests under `packages/playground/` for integration tests, packages might contains unit tests under their `__tests__` directory. Unit tests are powered by [Vitest](https://vitest.dev/). The detailed config is inside `vitest.config.ts` files.

- `pnpm run test-unit` runs unit tests under each package.

- You can also use `pnpm run test-unit -- [match]` to run related tests.

### Test Env and Helpers

Inside playground tests, a global `page` object is automatically available, which is a Playwright [`Page`](https://playwright.dev/docs/api/class-page) instance that has already navigated to the served page of the current playground. So writing a test is as simple as:
Expand Down
4 changes: 1 addition & 3 deletions jest.config.ts
Expand Up @@ -3,9 +3,7 @@ import type { Config } from '@jest/types'

const config: Config.InitialOptions = {
preset: 'ts-jest',
testMatch: process.env.VITE_TEST_BUILD
? ['**/playground/**/*.spec.[jt]s?(x)']
: ['**/*.spec.[jt]s?(x)'],
testMatch: ['**/playground/**/*.spec.[jt]s?(x)'],
testTimeout: process.env.CI ? 50000 : 20000,
globalSetup: './scripts/jestGlobalSetup.cjs',
globalTeardown: './scripts/jestGlobalTeardown.cjs',
Expand Down
8 changes: 5 additions & 3 deletions package.json
Expand Up @@ -16,10 +16,11 @@
"preinstall": "npx only-allow pnpm",
"format": "prettier --write .",
"lint": "eslint packages/*/{src,types}/**",
"test": "run-s test-serve test-build",
"test": "run-s test-serve test-build test-unit",
"test-serve": "jest",
"debug-serve": "cross-env VITE_DEBUG_SERVE=1 node --inspect-brk ./node_modules/.bin/jest",
"test-build": "cross-env VITE_TEST_BUILD=1 jest",
"test-unit": "vitest run",
"debug-serve": "cross-env VITE_DEBUG_SERVE=1 node --inspect-brk ./node_modules/.bin/jest",
"debug-build": "cross-env VITE_TEST_BUILD=1 VITE_PRESERVE_BUILD_ARTIFACTS=1 node --inspect-brk ./node_modules/.bin/jest",
"docs": "vitepress dev docs",
"build-docs": "vitepress build docs",
Expand Down Expand Up @@ -68,7 +69,8 @@
"ts-node": "^10.4.0",
"typescript": "~4.5.4",
"vite": "workspace:*",
"vitepress": "^0.22.3"
"vitepress": "^0.22.3",
"vitest": "^0.10.4"
},
"simple-git-hooks": {
"pre-commit": "pnpm exec lint-staged --concurrent false",
Expand Down
1 change: 1 addition & 0 deletions packages/create-vite/__tests__/cli.spec.ts
Expand Up @@ -3,6 +3,7 @@ import type { ExecaSyncReturnValue, SyncOptions } from 'execa'
import { commandSync } from 'execa'
import { mkdirpSync, readdirSync, remove, writeFileSync } from 'fs-extra'
import { join } from 'path'
import { test, expect, beforeAll, afterEach } from 'vitest'

const CLI_PATH = join(__dirname, '..')

Expand Down
@@ -1,5 +1,6 @@
import babelRestoreJSX from './babel-restore-jsx'
import * as babel from '@babel/core'
import { describe, it, expect } from 'vitest'

function jsx(code: string) {
return babel.transform(code, {
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-react/src/jsx-runtime/restore-jsx.spec.ts
@@ -1,5 +1,6 @@
import { restoreJSX } from './restore-jsx'
import * as babel from '@babel/core'
import { describe, it, expect } from 'vitest'

async function jsx(sourceCode: string) {
const [ast] = await restoreJSX(babel, sourceCode, 'test.js')
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/asset.spec.ts
@@ -1,3 +1,4 @@
import { describe, test, expect } from 'vitest'
import { assetFileNamesToFileName, getAssetHash } from '../plugins/asset'

describe('getAssetHash', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/build.spec.ts
@@ -1,6 +1,7 @@
import type { LibraryFormats, LibraryOptions } from '../build'
import { resolveLibFilename } from '../build'
import { resolve } from 'path'
import { describe, test, expect } from 'vitest'

type FormatsToFileNames = [LibraryFormats, string][]
const baseLibOptions: LibraryOptions = {
Expand Down
Binary file modified packages/vite/src/node/__tests__/cleanString.spec.ts
Binary file not shown.
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/config.spec.ts
@@ -1,6 +1,7 @@
import type { InlineConfig } from '..'
import type { UserConfigExport, UserConfig } from '../config'
import { mergeConfig, resolveConfig, resolveEnvPrefix } from '../config'
import { describe, test, expect } from 'vitest'

describe('mergeConfig', () => {
test('handles configs with different alias schemas', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/dev.spec.ts
@@ -1,4 +1,5 @@
import { resolveConfig } from '..'
import { describe, test, expect } from 'vitest'

describe('resolveBuildOptions in dev', () => {
test('build.rollupOptions should not have input in lib', async () => {
Expand Down
3 changes: 2 additions & 1 deletion packages/vite/src/node/__tests__/plugins/css.spec.ts
Expand Up @@ -2,6 +2,7 @@ import { cssUrlRE, cssPlugin, hoistAtRules } from '../../plugins/css'
import { resolveConfig } from '../../config'
import fs from 'fs'
import path from 'path'
import { describe, vi, test, expect } from 'vitest'

describe('search css url function', () => {
test('some spaces before it', () => {
Expand Down Expand Up @@ -69,7 +70,7 @@ describe('css path resolutions', () => {

await buildStart.call({})

const mockFs = jest
const mockFs = vi
.spyOn(fs, 'readFile')
// @ts-ignore jest.spyOn not recognize overrided `fs.readFile` definition.
.mockImplementationOnce((p, encoding, callback) => {
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/plugins/define.spec.ts
@@ -1,3 +1,4 @@
import { describe, test, expect } from 'vitest'
import { definePlugin } from '../../plugins/define'
import { resolveConfig } from '../../config'

Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/plugins/import.spec.ts
@@ -1,3 +1,4 @@
import { describe, test, expect } from 'vitest'
import { transformCjsImport } from '../../plugins/importAnalysis'

describe('transformCjsImport', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/scan.spec.ts
@@ -1,5 +1,6 @@
import { scriptRE, commentRE, importsRE } from '../optimizer/scan'
import { multilineCommentsRE, singlelineCommentsRE } from '../utils'
import { describe, test, expect } from 'vitest'

describe('optimizer-scan:script-test', () => {
const scriptContent = `import { defineComponent } from 'vue'
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/__tests__/utils.spec.ts
Expand Up @@ -4,6 +4,7 @@ import {
isWindows,
resolveHostname
} from '../utils'
import { describe, test, expect } from 'vitest'

describe('injectQuery', () => {
if (isWindows) {
Expand Down
9 changes: 6 additions & 3 deletions packages/vite/src/node/cleanString.ts
Expand Up @@ -5,6 +5,7 @@ import { multilineCommentsRE, singlelineCommentsRE } from './utils'
// /`([^`\$\{\}]|\$\{(`|\g<1>)*\})*`/g can match nested string template
// but js not support match expression(\g<0>). so clean string template(`...`) in other ways.
const stringsRE = /"([^"\r\n]|(?<=\\)")*"|'([^'\r\n]|(?<=\\)')*'/g
const regexRE = /\/.*?(?<!\\)\/[gimsuy]*/g
const cleanerRE = new RegExp(
`${stringsRE.source}|${multilineCommentsRE.source}|${singlelineCommentsRE.source}`,
'g'
Expand All @@ -15,9 +16,11 @@ const stringBlankReplacer = (s: string) =>
`${s[0]}${'\0'.repeat(s.length - 2)}${s[0]}`

export function emptyString(raw: string): string {
let res = raw.replace(cleanerRE, (s: string) =>
s[0] === '/' ? blankReplacer(s) : stringBlankReplacer(s)
)
let res = raw
.replace(cleanerRE, (s: string) =>
s[0] === '/' ? blankReplacer(s) : stringBlankReplacer(s)
)
.replace(regexRE, (s) => stringBlankReplacer(s))

let lastEnd = 0
let start = 0
Expand Down
Expand Up @@ -4,6 +4,7 @@ import type { Plugin } from '../../plugin'
import { ModuleGraph } from '../moduleGraph'
import type { PluginContainer } from '../pluginContainer'
import { createPluginContainer } from '../pluginContainer'
import { describe, it, expect, beforeEach } from 'vitest'

let resolveId: (id: string) => any
let moduleGraph: ModuleGraph
Expand Down
@@ -1,5 +1,6 @@
import { searchForWorkspaceRoot } from '../searchRoot'
import { resolve } from 'path'
import { describe, test, expect } from 'vitest'

describe('searchForWorkspaceRoot', () => {
test('lerna', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts
@@ -1,4 +1,5 @@
import { stripNesting } from '../ssrExternal'
import { test, expect } from 'vitest'

test('stripNesting', async () => {
expect(stripNesting(['c', 'p1>c1', 'p2 > c2'])).toEqual(['c', 'c1', 'c2'])
Expand Down
3 changes: 2 additions & 1 deletion packages/vite/src/node/ssr/__tests__/ssrModuleLoader.spec.ts
@@ -1,12 +1,13 @@
import { resolve } from 'path'
import { createServer } from '../../index'
import { test, vi, expect } from 'vitest'

const badjs = resolve(__dirname, './fixtures/ssrModuleLoader-bad.js')
const THROW_MESSAGE = 'it is an expected error'

test('always throw error when evaluating an wrong SSR module', async () => {
const viteServer = await createServer()
const spy = jest.spyOn(console, 'error').mockImplementation(() => {})
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
const expectedErrors = []
for (const i of [0, 1]) {
try {
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts
@@ -1,6 +1,7 @@
import { transformWithEsbuild } from '../../plugins/esbuild'
import { traverseHtml } from '../../plugins/html'
import { ssrTransform } from '../ssrTransform'
import { test, expect } from 'vitest'

test('default import', async () => {
expect(
Expand Down

0 comments on commit 63cd53d

Please sign in to comment.