Skip to content

Commit

Permalink
fix(browser): inline pretty-format and replace picocolors with tinyra…
Browse files Browse the repository at this point in the history
…inbow (#6077)
  • Loading branch information
sheremet-va authored Jul 10, 2024
1 parent 7f0cc24 commit 80a43d5
Show file tree
Hide file tree
Showing 108 changed files with 2,218 additions and 415 deletions.
2 changes: 1 addition & 1 deletion docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2181,7 +2181,7 @@ Path to a diff config that will be used to generate diff interface. Useful if yo
:::code-group
```ts [vitest.diff.ts]
import type { DiffOptions } from 'vitest'
import c from 'picocolors'
import c from 'tinyrainbow'

export default {
aIndicator: c.bold('--'),
Expand Down
3 changes: 3 additions & 0 deletions packages/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
"types": "./context.d.ts",
"default": "./context.js"
},
"./client": {
"default": "./dist/client.js"
},
"./matchers": {
"types": "./matchers.d.ts"
},
Expand Down
15 changes: 15 additions & 0 deletions packages/browser/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ export default () =>
}),
],
},
{
input: './src/client/client.ts',
output: {
file: 'dist/client.js',
format: 'esm',
},
plugins: [
resolve({
preferBuiltins: true,
}),
esbuild({
target: 'node18',
}),
],
},
{
input: './src/client/tester/state.ts',
output: {
Expand Down
4 changes: 2 additions & 2 deletions packages/browser/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getBrowserState } from './utils'

const PAGE_TYPE = getBrowserState().type

export const PORT = import.meta.hot ? '51204' : location.port
export const PORT = location.port
export const HOST = [location.hostname, PORT].filter(Boolean).join(':')
export const SESSION_ID
= PAGE_TYPE === 'orchestrator'
Expand Down Expand Up @@ -136,4 +136,4 @@ function createClient() {

export const client = createClient()

export { channel, waitForChannel } from './channel'
export * from './channel'
3 changes: 2 additions & 1 deletion packages/browser/src/client/orchestrator.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
height: 100%;
}
</style>
<script>{__VITEST_INJECTOR__}</script>
{__VITEST_INJECTOR__}
{__VITEST_ERROR_CATCHER__}
{__VITEST_SCRIPTS__}
</head>
<body>
Expand Down
4 changes: 2 additions & 2 deletions packages/browser/src/client/orchestrator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { ResolvedConfig } from 'vitest'
import { channel, client } from '@vitest/browser/client'
import { generateHash } from '@vitest/runner/utils'
import { type GlobalChannelIncomingEvent, type IframeChannelEvent, type IframeChannelIncomingEvent, globalChannel } from '@vitest/browser/client'
import { relative } from 'pathe'
import { channel, client } from './client'
import { getBrowserState, getConfig } from './utils'
import { getUiAPI } from './ui'
import { type GlobalChannelIncomingEvent, type IframeChannelEvent, type IframeChannelIncomingEvent, globalChannel } from './channel'
import { createModuleMocker } from './tester/msw'

const url = new URL(location.href)
Expand Down
81 changes: 81 additions & 0 deletions packages/browser/src/client/public/error-catcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { channel, client } from '/@id/@vitest/browser/client'

function on(event, listener) {
window.addEventListener(event, listener)
return () => window.removeEventListener(event, listener)
}

function serializeError(unhandledError) {
if (typeof unhandledError !== 'object' || !unhandledError) {
return {
message: String(unhandledError),
}
}

return {
name: unhandledError.name,
message: unhandledError.message,
stack: String(unhandledError.stack),
}
}

function catchWindowErrors(cb) {
let userErrorListenerCount = 0
function throwUnhandlerError(e) {
if (userErrorListenerCount === 0 && e.error != null) {
cb(e)
}
else {
console.error(e.error)
}
}
const addEventListener = window.addEventListener.bind(window)
const removeEventListener = window.removeEventListener.bind(window)
window.addEventListener('error', throwUnhandlerError)
window.addEventListener = function (...args) {
if (args[0] === 'error') {
userErrorListenerCount++
}
return addEventListener.apply(this, args)
}
window.removeEventListener = function (...args) {
if (args[0] === 'error' && userErrorListenerCount) {
userErrorListenerCount--
}
return removeEventListener.apply(this, args)
}
return function clearErrorHandlers() {
window.removeEventListener('error', throwUnhandlerError)
}
}

function registerUnexpectedErrors() {
catchWindowErrors(event =>
reportUnexpectedError('Error', event.error),
)
on('unhandledrejection', event =>
reportUnexpectedError('Unhandled Rejection', event.reason))
}

async function reportUnexpectedError(
type,
error,
) {
const processedError = serializeError(error)
await client.rpc.onUnhandledError(processedError, type)
const state = __vitest_browser_runner__

if (state.type === 'orchestrator') {
return
}

if (!state.runTests || !__vitest_worker__.current) {
channel.postMessage({
type: 'done',
filenames: state.files,
id: state.iframeId,
})
}
}

registerUnexpectedErrors()
2 changes: 1 addition & 1 deletion packages/browser/src/client/tester/context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Task, WorkerGlobalState } from 'vitest'
import type { BrowserRPC } from '@vitest/browser/client'
import type { BrowserPage, UserEvent, UserEventClickOptions, UserEventTabOptions, UserEventTypeOptions } from '../../../context'
import type { BrowserRunnerState } from '../utils'
import type { BrowserRPC } from '../client'

// this file should not import anything directly, only types

Expand Down
4 changes: 2 additions & 2 deletions packages/browser/src/client/tester/mocker.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { getType } from '@vitest/utils'
import { extname, join } from 'pathe'
import type { IframeChannelOutgoingEvent } from '@vitest/browser/client'
import { channel, waitForChannel } from '@vitest/browser/client'
import { getBrowserState, importId } from '../utils'
import type { IframeChannelOutgoingEvent } from '../channel'
import { channel, waitForChannel } from '../client'
import { rpc } from './rpc'

const now = Date.now
Expand Down
4 changes: 2 additions & 2 deletions packages/browser/src/client/tester/msw.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { channel } from '@vitest/browser/client'
import type {
IframeChannelEvent,
IframeMockEvent,
IframeMockingDoneEvent,
IframeUnmockEvent,
} from '../channel'
import { channel } from '../channel'
} from '@vitest/browser/client'

export function createModuleMocker() {
const mocks: Map<string, string | null | undefined> = new Map()
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/src/client/tester/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getSafeTimers } from 'vitest/utils'
import type { VitestBrowserClient } from '../client'
import type { VitestBrowserClient } from '@vitest/browser/client'

const { get } = Reflect

Expand Down
2 changes: 1 addition & 1 deletion packages/browser/src/client/tester/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { NodeBenchmarkRunner, VitestTestRunner } from 'vitest/runners'
import { loadDiffConfig, loadSnapshotSerializers, takeCoverageInsideWorker } from 'vitest/browser'
import { TraceMap, originalPositionFor } from 'vitest/utils'
import { page } from '@vitest/browser/context'
import { globalChannel } from '@vitest/browser/client'
import { importFs, importId } from '../utils'
import { globalChannel } from '../channel'
import { VitestBrowserSnapshotEnvironment } from './snapshot'
import { rpc } from './rpc'
import type { VitestBrowserClientMocker } from './mocker'
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/src/client/tester/snapshot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SnapshotEnvironment } from 'vitest/snapshot'
import { type ParsedStack, TraceMap, originalPositionFor } from 'vitest/utils'
import type { VitestBrowserClient } from '../client'
import type { VitestBrowserClient } from '@vitest/browser/client'

export class VitestBrowserSnapshotEnvironment implements SnapshotEnvironment {
private sourceMaps = new Map<string, any>()
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/src/client/tester/state.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { WorkerGlobalState } from 'vitest'
import { parse } from 'flatted'
import type { BrowserRPC } from '@vitest/browser/client'
import { getBrowserState } from '../utils'
import type { BrowserRPC } from '../client'

const config = getBrowserState().config
const contextId = getBrowserState().contextId
Expand Down
3 changes: 2 additions & 1 deletion packages/browser/src/client/tester/tester.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
min-height: 100vh;
}
</style>
<script>{__VITEST_INJECTOR__}</script>
{__VITEST_INJECTOR__}
<script>{__VITEST_STATE__}</script>
{__VITEST_ERROR_CATCHER__}
{__VITEST_SCRIPTS__}
</head>
<body
Expand Down
14 changes: 6 additions & 8 deletions packages/browser/src/client/tester/tester.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { SpyModule, collectTests, setupCommonEnv, startTests } from 'vitest/browser'
import { channel, client, onCancel } from '@vitest/browser/client'
import { getBrowserState, getConfig, getWorkerState } from '../utils'
import { channel, client, onCancel } from '../client'
import { setupDialogsSpy } from './dialog'
import {
registerUnexpectedErrors,
serializeError,
} from './unhandled'
import { setupConsoleLogSpy } from './logger'
import { createSafeRpc } from './rpc'
import { browserHashMap, initiateRunner } from './runner'
Expand Down Expand Up @@ -59,8 +55,6 @@ async function prepareTestEnvironment(files: string[]) {
runner.onCancel?.(reason)
})

registerUnexpectedErrors(rpc)

return {
runner,
config,
Expand Down Expand Up @@ -92,7 +86,11 @@ async function executeTests(method: 'run' | 'collect', files: string[]) {
}
catch (error: any) {
debug('runner cannot be loaded because it threw an error', error.stack || error.message)
await client.rpc.onUnhandledError(serializeError(error), 'Preload Error')
await client.rpc.onUnhandledError({
name: error.name,
message: error.message,
stack: String(error.stack),
}, 'Preload Error')
done(files)
return
}
Expand Down
25 changes: 15 additions & 10 deletions packages/browser/src/client/tester/unhandled.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { processError } from 'vitest/browser'
import type { client } from '../client'
import { client } from '@vitest/browser/client'

function on(event: string, listener: (...args: any[]) => void) {
window.addEventListener(event, listener)
return () => window.removeEventListener(event, listener)
}

export function serializeError(unhandledError: any) {
function serializeError(unhandledError: any) {
if (typeof unhandledError !== 'object' || !unhandledError) {
return {
message: String(unhandledError),
}
}

return {
...unhandledError,
name: unhandledError.name,
message: unhandledError.message,
stack: String(unhandledError.stack),
Expand Down Expand Up @@ -49,19 +53,20 @@ function catchWindowErrors(cb: (e: ErrorEvent) => void) {
}
}

export function registerUnexpectedErrors(rpc: typeof client.rpc) {
function registerUnexpectedErrors() {
catchWindowErrors(event =>
reportUnexpectedError(rpc, 'Error', event.error),
reportUnexpectedError('Error', event.error),
)
on('unhandledrejection', event =>
reportUnexpectedError(rpc, 'Unhandled Rejection', event.reason))
reportUnexpectedError('Unhandled Rejection', event.reason))
}

async function reportUnexpectedError(
rpc: typeof client.rpc,
type: string,
error: any,
) {
const processedError = processError(error)
await rpc.onUnhandledError(processedError, type)
const processedError = serializeError(error)
await client.rpc.onUnhandledError(processedError, type)
}

registerUnexpectedErrors()
8 changes: 7 additions & 1 deletion packages/browser/src/client/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ export default defineConfig({
orchestrator: resolve(__dirname, './orchestrator.html'),
tester: resolve(__dirname, './tester/tester.html'),
},
external: [/^vitest\//, 'vitest', /^msw/, '@vitest/browser/context'],
external: [
/^vitest\//,
'vitest',
/^msw/,
'@vitest/browser/context',
'@vitest/browser/client',
],
},
},
plugins: [
Expand Down
7 changes: 1 addition & 6 deletions packages/browser/src/node/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,20 +178,15 @@ export default (browserServer: BrowserServer, base = '/'): Plugin[] => {
'std-env',
'tinybench',
'tinyspy',
'tinyrainbow',
'pathe',
'msw',
'msw/browser',
],
include: [
'vitest > @vitest/utils > pretty-format',
'vitest > @vitest/snapshot > pretty-format',
'vitest > @vitest/snapshot > magic-string',
'vitest > pretty-format',
'vitest > pretty-format > ansi-styles',
'vitest > pretty-format > ansi-regex',
'vitest > chai',
'vitest > chai > loupe',
'vitest > @vitest/utils > diff-sequences',
'vitest > @vitest/utils > loupe',
'@vitest/browser > @testing-library/user-event',
'@vitest/browser > @testing-library/dom',
Expand Down
5 changes: 5 additions & 0 deletions packages/browser/src/node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class BrowserServer implements IBrowserServer {
public testerHtml: Promise<string> | string
public orchestratorHtml: Promise<string> | string
public injectorJs: Promise<string> | string
public errorCatcherJs: Promise<string> | string
public stateJs: Promise<string> | string

public state: BrowserServerState
Expand Down Expand Up @@ -86,6 +87,10 @@ export class BrowserServer implements IBrowserServer {
resolve(distRoot, 'client/esm-client-injector.js'),
'utf8',
).then(js => (this.injectorJs = js))
this.errorCatcherJs = readFile(
resolve(distRoot, 'client/error-catcher.js'),
'utf8',
).then(js => (this.errorCatcherJs = js))
this.stateJs = readFile(
resolve(distRoot, 'state.js'),
'utf-8',
Expand Down
6 changes: 4 additions & 2 deletions packages/browser/src/node/serverOrchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ export async function resolveOrchestrator(
.replace(
'<!-- !LOAD_METADATA! -->',
[
'<script>{__VITEST_INJECTOR__}</script>',
'{__VITEST_INJECTOR__}',
'{__VITEST_ERROR_CATCHER__}',
'{__VITEST_SCRIPTS__}',
`<script type="module" crossorigin src="${base}${jsEntry}"></script>`,
].join('\n'),
Expand All @@ -70,7 +71,8 @@ export async function resolveOrchestrator(
__VITEST_FAVICON__: server.faviconUrl,
__VITEST_TITLE__: 'Vitest Browser Runner',
__VITEST_SCRIPTS__: server.orchestratorScripts,
__VITEST_INJECTOR__: injector,
__VITEST_INJECTOR__: `<script type="module">${injector}</script>`,
__VITEST_ERROR_CATCHER__: `<script type="module">${server.errorCatcherJs}</script>`,
__VITEST_CONTEXT_ID__: JSON.stringify(contextId),
})
}
Loading

0 comments on commit 80a43d5

Please sign in to comment.