fix: use Vitest for unit testing, clean regex bug (#8040)

This commit is contained in:
Anthony Fu 2022-05-06 16:00:31 +08:00 committed by GitHub
parent c7eeb8d692
commit 63cd53d248
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 160 additions and 15 deletions

View File

@ -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': [
@ -103,7 +103,7 @@ module.exports = defineConfig({
}
},
{
files: ['packages/vite/types/**'],
files: ['packages/vite/types/**', '*.spec.ts'],
rules: {
'node/no-extraneous-import': 'off'
}

View File

@ -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

View File

@ -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`.
@ -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:

View File

@ -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',

View File

@ -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",
@ -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",

View File

@ -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, '..')

View File

@ -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, {

View File

@ -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')

View File

@ -1,3 +1,4 @@
import { describe, test, expect } from 'vitest'
import { assetFileNamesToFileName, getAssetHash } from '../plugins/asset'
describe('getAssetHash', () => {

View File

@ -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 = {

View File

@ -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', () => {

View File

@ -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 () => {

View File

@ -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', () => {
@ -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) => {

View File

@ -1,3 +1,4 @@
import { describe, test, expect } from 'vitest'
import { definePlugin } from '../../plugins/define'
import { resolveConfig } from '../../config'

View File

@ -1,3 +1,4 @@
import { describe, test, expect } from 'vitest'
import { transformCjsImport } from '../../plugins/importAnalysis'
describe('transformCjsImport', () => {

View File

@ -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'

View File

@ -4,6 +4,7 @@ import {
isWindows,
resolveHostname
} from '../utils'
import { describe, test, expect } from 'vitest'
describe('injectQuery', () => {
if (isWindows) {

View File

@ -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'
@ -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

View File

@ -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

View File

@ -1,5 +1,6 @@
import { searchForWorkspaceRoot } from '../searchRoot'
import { resolve } from 'path'
import { describe, test, expect } from 'vitest'
describe('searchForWorkspaceRoot', () => {
test('lerna', () => {

View File

@ -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'])

View File

@ -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 {

View File

@ -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(

View File

@ -45,6 +45,7 @@ importers:
typescript: ~4.5.4
vite: workspace:*
vitepress: ^0.22.3
vitest: ^0.10.4
devDependencies:
'@microsoft/api-extractor': 7.23.0
'@types/fs-extra': 9.0.13
@ -81,6 +82,7 @@ importers:
typescript: 4.5.4
vite: link:packages/vite
vitepress: 0.22.3
vitest: 0.10.4
packages/create-vite:
specifiers:
@ -2579,6 +2581,16 @@ packages:
resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==}
dev: true
/@types/chai-subset/1.3.3:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
dependencies:
'@types/chai': 4.3.1
dev: true
/@types/chai/4.3.1:
resolution: {integrity: sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==}
dev: true
/@types/convert-source-map/1.5.2:
resolution: {integrity: sha512-tHs++ZeXer40kCF2JpE51Hg7t4HPa18B1b1Dzy96S0eCw8QKECNMYMfwa1edK/x8yCN0r4e6ewvLcc5CsVGkdg==}
dev: true
@ -3370,6 +3382,10 @@ packages:
resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==}
dev: true
/assertion-error/1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
dev: true
/astral-regex/2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
@ -3666,6 +3682,19 @@ packages:
resolution: {integrity: sha512-kbaCEBRRVSoeNs74sCuq92MJyGrMtjWVfhltoHUCW4t4pXFvGjUBrfo47weBRViHkiV3eBYyIsfl956NtHGazw==}
dev: false
/chai/4.3.6:
resolution: {integrity: sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==}
engines: {node: '>=4'}
dependencies:
assertion-error: 1.1.0
check-error: 1.0.2
deep-eql: 3.0.1
get-func-name: 2.0.0
loupe: 2.3.4
pathval: 1.1.1
type-detect: 4.0.8
dev: true
/chalk/2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@ -3692,6 +3721,10 @@ packages:
is-regex: 1.1.4
dev: true
/check-error/1.0.2:
resolution: {integrity: sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=}
dev: true
/chokidar/3.5.2:
resolution: {integrity: sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==}
engines: {node: '>= 8.10.0'}
@ -4374,6 +4407,13 @@ packages:
resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=}
dev: true
/deep-eql/3.0.1:
resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==}
engines: {node: '>=0.12'}
dependencies:
type-detect: 4.0.8
dev: true
/deep-is/0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
@ -5356,6 +5396,10 @@ packages:
engines: {node: 6.* || 8.* || >= 10.*}
dev: true
/get-func-name/2.0.0:
resolution: {integrity: sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=}
dev: true
/get-intrinsic/1.1.1:
resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==}
dependencies:
@ -6786,6 +6830,11 @@ packages:
engines: {node: '>= 12.13.0'}
dev: true
/local-pkg/0.4.1:
resolution: {integrity: sha512-lL87ytIGP2FU5PWwNDo0w3WhIo2gopIAxPg9RxDYF7m4rr5ahuZxP22xnJHIvaLTe4Z9P6uKKY2UHiwyB4pcrw==}
engines: {node: '>=14'}
dev: true
/locate-path/2.0.0:
resolution: {integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=}
engines: {node: '>=4'}
@ -6869,6 +6918,12 @@ packages:
js-tokens: 4.0.0
dev: false
/loupe/2.3.4:
resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==}
dependencies:
get-func-name: 2.0.0
dev: true
/lru-cache/6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
@ -7560,6 +7615,10 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
/pathval/1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
dev: true
/pend/1.2.0:
resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=}
dev: true
@ -9242,6 +9301,16 @@ packages:
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
dev: false
/tinypool/0.1.3:
resolution: {integrity: sha512-2IfcQh7CP46XGWGGbdyO4pjcKqsmVqFAPcXfPxcPXmOWt9cYkTP9HcDmGgsfijYoAEc4z9qcpM/BaBz46Y9/CQ==}
engines: {node: '>=14.0.0'}
dev: true
/tinyspy/0.3.2:
resolution: {integrity: sha512-2+40EP4D3sFYy42UkgkFFB+kiX2Tg3URG/lVvAZFfLxgGpnWl5qQJuBw1gaLttq8UOS+2p3C0WrhJnQigLTT2Q==}
engines: {node: '>=14.0.0'}
dev: true
/tmp/0.2.1:
resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
engines: {node: '>=8.17.0'}
@ -9623,6 +9692,34 @@ packages:
- react-dom
dev: true
/vitest/0.10.4:
resolution: {integrity: sha512-FJ2av2PVozmyz9nqHRoC3H8j2z0OQXj8P8jS5oyMY9mfPWB06GS5k/1Ot++TkVBLQRHZCcVzjbK4BO7zqAJZGQ==}
engines: {node: '>=v14.16.0'}
hasBin: true
peerDependencies:
'@vitest/ui': '*'
c8: '*'
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@vitest/ui':
optional: true
c8:
optional: true
happy-dom:
optional: true
jsdom:
optional: true
dependencies:
'@types/chai': 4.3.1
'@types/chai-subset': 1.3.3
chai: 4.3.6
local-pkg: 0.4.1
tinypool: 0.1.3
tinyspy: 0.3.2
vite: link:packages/vite
dev: true
/void-elements/3.1.0:
resolution: {integrity: sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=}
engines: {node: '>=0.10.0'}

15
vitest.config.ts Normal file
View File

@ -0,0 +1,15 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
exclude: [
'**/node_modules/**',
'**/dist/**',
'./packages/playground/**/*.*',
'./packages/temp/**/*.*'
]
},
esbuild: {
target: 'node14'
}
})