Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: html report #2444

Merged
merged 56 commits into from Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
ce4adb5
feat: vitest html report
poyoho Dec 6, 2022
d85c92c
chore: copy ui to vitest dist
poyoho Dec 6, 2022
a659179
feat: report copy ui dist
poyoho Dec 6, 2022
8c32d50
feat: ui report version builder
poyoho Dec 6, 2022
9208d4c
fix: copy file
poyoho Dec 6, 2022
758055c
chore: remove
poyoho Dec 6, 2022
3d77273
feat: html metadata path
poyoho Dec 6, 2022
2ddea5c
feat: add declare
poyoho Dec 6, 2022
7d374c9
feat: static file client
poyoho Dec 6, 2022
36bd86d
feat: mock rpc
poyoho Dec 6, 2022
cb29f14
fix: mock error
poyoho Dec 6, 2022
6b5bb57
chore: update meta
poyoho Dec 6, 2022
8c15597
chore: compress json
poyoho Dec 6, 2022
da5d3f2
chore: comment
poyoho Dec 7, 2022
9d4c650
chore: update merge config
poyoho Dec 7, 2022
35748fd
chore: update
poyoho Dec 7, 2022
d8d5680
chore: lock
poyoho Dec 7, 2022
b9511ca
feat: remove all control command from ui
poyoho Dec 7, 2022
936d109
chore: remove
poyoho Dec 7, 2022
a3baa19
feat: report command
poyoho Dec 7, 2022
bc7c2e9
feat: version tag
poyoho Dec 7, 2022
185db64
chore: reset lock file
poyoho Dec 7, 2022
dfa6073
feat: remove hooks
poyoho Dec 7, 2022
da71d8f
chore: update
poyoho Dec 7, 2022
9865a46
fix: runningPromise
poyoho Dec 7, 2022
6315cc1
Merge branch 'main' into html-report
poyoho Dec 7, 2022
7a3a382
chore: update debug mode and disable click on transform
poyoho Dec 7, 2022
5bfb5d6
docs: report
poyoho Dec 8, 2022
8f5bcc4
chore: remove the version mark
poyoho Dec 8, 2022
3a7b970
Merge branch 'main' into html-report
sheremet-va Dec 13, 2022
86bd94a
feat: report
poyoho Dec 13, 2022
5047e4b
fix: lint
poyoho Dec 13, 2022
9da35db
chore: copy ui from @vitest/ui
poyoho Dec 13, 2022
5969958
chore: export report from ui
poyoho Dec 13, 2022
dc8e406
chore: update
poyoho Dec 13, 2022
6c42ad7
fix: lint
poyoho Dec 13, 2022
d3f43da
docs: ui html report
poyoho Dec 13, 2022
ff951da
feat: ensurePackageInstalled
poyoho Dec 14, 2022
b807e7d
update
poyoho Dec 14, 2022
56a4285
feat: more info
poyoho Dec 14, 2022
da3263f
Merge branch 'main' into html-report
sheremet-va Dec 16, 2022
082f2b1
chore: improve documentation and tests
sheremet-va Dec 16, 2022
c94b627
chore: fix UI bundle size
sheremet-va Dec 16, 2022
78f344d
chore: ui tests
sheremet-va Dec 16, 2022
3bac646
perf: remove output report using the global variable to judge report …
poyoho Dec 17, 2022
966d59b
chore: update
poyoho Dec 17, 2022
e0c346d
fix: build
poyoho Dec 17, 2022
d941bf7
fix: report
poyoho Dec 17, 2022
8e41f66
fix: parse
poyoho Dec 17, 2022
0fcd30d
chore: fix html reporters test
sheremet-va Dec 17, 2022
6561232
chore: don't store config in html reporter test
sheremet-va Dec 17, 2022
9f6d669
chore: update ui docs
sheremet-va Dec 17, 2022
9e34e9a
feat: log
poyoho Dec 17, 2022
e03b564
chore: fix tests
sheremet-va Dec 17, 2022
1eb857f
test: fix html reporter tests
sheremet-va Dec 17, 2022
c1e04c2
docs add vitest fo UI reporter
sheremet-va Dec 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -2,8 +2,9 @@ import { createClient, getTasks } from '@vitest/ws-client'
import type { WebSocketStatus } from '@vueuse/core'
import type { Ref } from 'vue'
import { reactive } from 'vue'
import type { RunState } from '../../types'
import { activeFileId } from './params'
import type { RunState } from '../../../types'
import { activeFileId } from '../params'
import { createStaticClient } from './static'
import type { File, ResolvedConfig } from '#types'

export const PORT = import.meta.hot ? '51204' : location.port
Expand All @@ -12,17 +13,24 @@ export const ENTRY_URL = `${location.protocol === 'https:' ? 'wss:' : 'ws:'}//${

export const testRunState: Ref<RunState> = ref('idle')

export const client = createClient(ENTRY_URL, {
reactive: reactive as any,
handlers: {
onTaskUpdate() {
testRunState.value = 'running'
},
onFinished() {
testRunState.value = 'idle'
},
},
})
export const client = (function createVitestClient() {
if (__REPORT__) {
return createStaticClient()
}
else {
return createClient(ENTRY_URL, {
reactive: reactive as any,
handlers: {
onTaskUpdate() {
testRunState.value = 'running'
},
onFinished() {
testRunState.value = 'idle'
},
},
})
}
})()

export const config = shallowRef<ResolvedConfig>({} as any)
export const status = ref<WebSocketStatus>('CONNECTING')
Expand Down Expand Up @@ -60,11 +68,15 @@ watch(
(ws) => {
status.value = 'CONNECTING'

ws.addEventListener('open', () => {
ws.addEventListener('open', async () => {
status.value = 'OPEN'
client.state.filesMap.clear()
client.rpc.getFiles().then(files => client.state.collectFiles(files))
client.rpc.getConfig().then(_config => config.value = _config)
const [files, _config] = await Promise.all([
client.rpc.getFiles(),
client.rpc.getConfig(),
])
client.state.collectFiles(files)
config.value = _config
})

ws.addEventListener('close', () => {
Expand Down
84 changes: 84 additions & 0 deletions packages/ui/client/composables/client/static.ts
@@ -0,0 +1,84 @@
import type { BirpcReturn } from 'birpc'
import type { VitestClient } from '@vitest/ws-client'
import type { WebSocketHandlers } from 'vitest/src/api/types'
import { parse } from 'flatted'
import type { File, ModuleGraphData, ResolvedConfig } from 'vitest/src/types'
import { StateManager } from '../../../../vitest/src/node/state'

interface HTMLReportMetadata {
paths: string[]
files: File[]
config: ResolvedConfig
moduleGraph: Record<string, ModuleGraphData>
}

const noop: any = () => {}
const asyncNoop: any = () => Promise.resolve()

export function createStaticClient(): VitestClient {
const ctx = reactive({
state: new StateManager(),
waitForConnection,
reconnect,
ws: new EventTarget(),
}) as VitestClient

ctx.state.filesMap = reactive(ctx.state.filesMap)
ctx.state.idMap = reactive(ctx.state.idMap)

let metadata!: HTMLReportMetadata

const rpc = {
getFiles: () => {
return metadata.files
},
getPaths: async () => {
return metadata.paths
},
getConfig: () => {
return metadata.config
},
getModuleGraph: async (id) => {
return metadata.moduleGraph[id]
},
getTransformResult: async (id) => {
return {
code: id,
source: '',
}
},
readFile: async (id) => {
return Promise.resolve(id)
},
onWatcherStart: asyncNoop,
onFinished: asyncNoop,
onCollected: asyncNoop,
onTaskUpdate: noop,
writeFile: asyncNoop,
rerun: asyncNoop,
updateSnapshot: asyncNoop,
} as WebSocketHandlers

ctx.rpc = rpc as any as BirpcReturn<WebSocketHandlers>

let openPromise: Promise<void>

function reconnect() {
registerMetadata()
}

async function registerMetadata() {
const res = await fetch(window.METADATA_PATH!)
metadata = parse(await res.text()) as HTMLReportMetadata
const event = new Event('open')
ctx.ws.dispatchEvent(event)
}

registerMetadata()

function waitForConnection() {
return openPromise
}

return ctx
}
6 changes: 6 additions & 0 deletions packages/ui/client/shim.d.ts
Expand Up @@ -7,3 +7,9 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any>
export default component
}

const __REPORT__: boolean

declare interface Window {
METADATA_PATH?: string
}
3 changes: 2 additions & 1 deletion packages/ui/index.html
Expand Up @@ -9,13 +9,14 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Readex+Pro:wght@300;400&display=swap" rel="stylesheet">
<script>
(function() {
(function () {
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
const setting = localStorage.getItem('vueuse-color-scheme') || 'auto'
if (setting === 'dark' || (prefersDark && setting !== 'light'))
document.documentElement.classList.toggle('dark', true)
})()
</script>
<!-- !LOAD_METADATA! -->
</head>
<body>
<div id="app"></div>
Expand Down
8 changes: 6 additions & 2 deletions packages/ui/package.json
Expand Up @@ -24,12 +24,15 @@
"dist"
],
"scripts": {
"build": "rimraf dist && pnpm build:node && pnpm build:client",
"build": "rimraf dist && pnpm build:node && pnpm build:client && pnpm build:report",
"build:client": "vite build",
"build:report": "vite build -c vite.report.config.ts",
"build:node": "rollup -c",
"dev:client": "vite",
"dev:report": "vite -c vite.report.config.ts",
"dev": "rollup -c --watch --watch.include=node",
"dev:ui": "run-p dev dev:client",
"dev:ui-report": "run-p dev dev:report",
"test:run": "cypress run --component",
"test:open": "cypress open --component",
"prepublishOnly": "pnpm build"
Expand Down Expand Up @@ -66,6 +69,7 @@
"vite": "^3.2.3",
"vite-plugin-pages": "^0.27.1",
"vue": "^3.2.41",
"vue-router": "^4.1.6"
"vue-router": "^4.1.6",
"defu": "^6.1.1"
}
}
1 change: 1 addition & 0 deletions packages/ui/public/html.meta.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/ui/vite.config.ts
Expand Up @@ -18,6 +18,9 @@ export const config: UserConfig = {
'@vitest/ws-client': `${resolve(__dirname, '../ws-client/src/index.ts')}`,
},
},
define: {
__REPORT__: false,
},
plugins: [
Vue(),
Unocss({
Expand Down
21 changes: 21 additions & 0 deletions packages/ui/vite.report.config.ts
@@ -0,0 +1,21 @@
import { defineConfig } from 'vite'
import defu from 'defu'
poyoho marked this conversation as resolved.
Show resolved Hide resolved
import { config } from './vite.config'

export default defineConfig(defu({
base: './',
build: {
outDir: 'dist/report',
},
define: {
__REPORT__: true,
},
plugins: [
{
name: 'debug-html-report',
transformIndexHtml(html) {
return html.replace('<!-- !LOAD_METADATA! -->', '<script>window.METADATA_PATH="/html.meta.json"</script>')
},
},
],
}, config))
5 changes: 3 additions & 2 deletions packages/vitest/package.json
Expand Up @@ -76,9 +76,10 @@
"node": ">=v14.16.0"
},
"scripts": {
"build": "rimraf dist && rollup -c",
"build": "rimraf dist && rollup -c && pnpm copy",
"dev": "NODE_OPTIONS=\"--max-old-space-size=8192\" rollup -c --watch -m inline",
"prepublishOnly": "pnpm build"
"prepublishOnly": "pnpm build",
"copy": "esno scripts/copy-ui-to-vitest.ts"
poyoho marked this conversation as resolved.
Show resolved Hide resolved
},
"peerDependencies": {
"@edge-runtime/vm": "*",
Expand Down
24 changes: 24 additions & 0 deletions packages/vitest/scripts/copy-ui-to-vitest.ts
@@ -0,0 +1,24 @@
import { fileURLToPath } from 'url'
import fs from 'fs'
import { resolve } from 'pathe'
import fg from 'fast-glob'

const root = resolve(fileURLToPath(import.meta.url), '../../../../packages')

const ui = resolve(root, 'ui/dist/report')
const vitest = resolve(root, 'vitest/dist/html-report/')

const files = fg.sync('**/*', { cwd: ui })
const originFiles = fg.sync('**/*', { cwd: vitest })

originFiles.forEach((f) => {
fs.unlinkSync(resolve(vitest, f))
})

if (!fs.existsSync(resolve(vitest, 'assets')))
fs.mkdirSync(resolve(vitest, 'assets'), { recursive: true })

files.forEach((f) => {
fs.copyFileSync(resolve(ui, f), resolve(vitest, f))
})

70 changes: 37 additions & 33 deletions packages/vitest/src/api/setup.ts
Expand Up @@ -10,6 +10,42 @@ import type { Vitest } from '../node'
import type { File, ModuleGraphData, Reporter, TaskResultPack, UserConsoleLog } from '../types'
import type { TransformResultWithSource, WebSocketEvents, WebSocketHandlers } from './types'

export async function getModuleGraph(ctx: Vitest, id: string): Promise<ModuleGraphData> {
const graph: Record<string, string[]> = {}
const externalized = new Set<string>()
const inlined = new Set<string>()

function clearId(id?: string | null) {
return id?.replace(/\?v=\w+$/, '') || ''
}
async function get(mod?: ModuleNode, seen = new Map<ModuleNode, string>()) {
if (!mod || !mod.id)
return
if (seen.has(mod))
return seen.get(mod)
let id = clearId(mod.id)
seen.set(mod, id)
const rewrote = await ctx.vitenode.shouldExternalize(id)
if (rewrote) {
id = rewrote
externalized.add(id)
seen.set(mod, id)
}
else {
inlined.add(id)
}
const mods = Array.from(mod.importedModules).filter(i => i.id && !i.id.includes('/vitest/dist/'))
graph[id] = (await Promise.all(mods.map(m => get(m, seen)))).filter(Boolean) as string[]
return id
}
await get(ctx.server.moduleGraph.getModuleById(id))
return {
graph,
externalized: Array.from(externalized),
inlined: Array.from(inlined),
}
}

export function setup(ctx: Vitest) {
const wss = new WebSocketServer({ noServer: true })

Expand Down Expand Up @@ -75,39 +111,7 @@ export function setup(ctx: Vitest) {
}
},
async getModuleGraph(id: string): Promise<ModuleGraphData> {
const graph: Record<string, string[]> = {}
const externalized = new Set<string>()
const inlined = new Set<string>()

function clearId(id?: string | null) {
return id?.replace(/\?v=\w+$/, '') || ''
}
async function get(mod?: ModuleNode, seen = new Map<ModuleNode, string>()) {
if (!mod || !mod.id)
return
if (seen.has(mod))
return seen.get(mod)
let id = clearId(mod.id)
seen.set(mod, id)
const rewrote = await ctx.vitenode.shouldExternalize(id)
if (rewrote) {
id = rewrote
externalized.add(id)
seen.set(mod, id)
}
else {
inlined.add(id)
}
const mods = Array.from(mod.importedModules).filter(i => i.id && !i.id.includes('/vitest/dist/'))
graph[id] = (await Promise.all(mods.map(m => get(m, seen)))).filter(Boolean) as string[]
return id
}
await get(ctx.server.moduleGraph.getModuleById(id))
return {
graph,
externalized: Array.from(externalized),
inlined: Array.from(inlined),
}
return getModuleGraph(ctx, id)
},
updateSnapshot(file?: File) {
if (!file)
Expand Down
4 changes: 3 additions & 1 deletion packages/vitest/src/node/core.ts
Expand Up @@ -341,9 +341,11 @@ export class Vitest {
this.cache.results.updateResults(files)
await this.cache.results.writeToCache()
})()
.finally(() => {
.finally(async () => {
this.runningPromise = undefined
poyoho marked this conversation as resolved.
Show resolved Hide resolved
this.state.finishCollectingPaths()
if (!this.config.browser)
await this.report('onFinally')
})

return await this.runningPromise
Expand Down