diff --git a/packages/ui/client/components/views/ViewConsoleOutput.vue b/packages/ui/client/components/views/ViewConsoleOutput.vue index f2b7ac179e25..afde92011c9e 100644 --- a/packages/ui/client/components/views/ViewConsoleOutput.vue +++ b/packages/ui/client/components/views/ViewConsoleOutput.vue @@ -3,18 +3,13 @@ import { getNames } from '@vitest/ws-client' import { client, currentLogs as logs } from '~/composables/client' import { isDark } from '~/composables/dark' import { createAnsiToHtmlFilter } from '~/composables/error' +import { escapeHtml } from "~/utils/escape" const formattedLogs = computed(() => { const data = logs.value if (data) { const filter = createAnsiToHtmlFilter(isDark.value) - return data.map(({ taskId, type, time, content }) => { - const trimmed = content.trim() - const value = filter.toHtml(trimmed) - return value !== trimmed - ? { taskId, type, time, html: true, content: value } - : { taskId, type, time, html: false, content } - }) + return data.map(({ taskId, type, time, content }) => ({ taskId, type, time, content: filter.toHtml(escapeHtml(content)) })) } }) @@ -26,13 +21,12 @@ function getTaskName(id?: string) { diff --git a/packages/ui/client/components/views/ViewReport.vue b/packages/ui/client/components/views/ViewReport.vue index 9e6c13754d2b..4e0e8fff9882 100644 --- a/packages/ui/client/components/views/ViewReport.vue +++ b/packages/ui/client/components/views/ViewReport.vue @@ -5,6 +5,7 @@ import ViewReportError from './ViewReportError.vue' import { isDark } from '~/composables/dark' import { createAnsiToHtmlFilter } from '~/composables/error' import { config } from '~/composables/client' +import { escapeHtml } from '~/utils/escape' const props = defineProps<{ file?: File @@ -24,15 +25,6 @@ function collectFailed(task: Task, level: number): LeveledTask[] { return [{ ...task, level }, ...task.tasks.flatMap(t => collectFailed(t, level + 1))] } -function escapeHtml(unsafe: string) { - return unsafe - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') -} - function createHtmlError(filter: Convert, error: ErrorWithDiff) { let htmlError = '' if (error.message?.includes('\x1B')) diff --git a/packages/ui/client/utils/escape.ts b/packages/ui/client/utils/escape.ts new file mode 100644 index 000000000000..27676fac160e --- /dev/null +++ b/packages/ui/client/utils/escape.ts @@ -0,0 +1,8 @@ +export function escapeHtml(unsafe: string) { + return unsafe + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7848f858af6..08024e98b5e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1909,9 +1909,12 @@ importers: '@playwright/test': specifier: ^1.39.0 version: 1.39.0 - execa: - specifier: ^6.1.0 - version: 6.1.0 + '@testing-library/dom': + specifier: ^9.3.3 + version: 9.3.3 + happy-dom: + specifier: latest + version: 12.10.3 vitest: specifier: workspace:* version: link:../../packages/vitest @@ -8386,8 +8389,8 @@ packages: dependencies: '@storybook/client-logger': 6.5.10 '@storybook/instrumenter': 6.5.10(react-dom@17.0.2)(react@17.0.2) - '@testing-library/dom': 8.17.1 - '@testing-library/user-event': 13.5.0(@testing-library/dom@8.17.1) + '@testing-library/dom': 8.19.0 + '@testing-library/user-event': 13.5.0(@testing-library/dom@8.19.0) ts-dedent: 2.2.0 transitivePeerDependencies: - react @@ -8640,20 +8643,6 @@ packages: cypress: 13.6.0 dev: true - /@testing-library/dom@8.17.1: - resolution: {integrity: sha512-KnH2MnJUzmFNPW6RIKfd+zf2Wue8mEKX0M3cpX6aKl5ZXrJM1/c/Pc8c2xDNYQCnJO48Sm5ITbMXgqTr3h4jxQ==} - engines: {node: '>=12'} - dependencies: - '@babel/code-frame': 7.22.13 - '@babel/runtime': 7.23.2 - '@types/aria-query': 4.2.2 - aria-query: 5.3.0 - chalk: 4.1.2 - dom-accessibility-api: 0.5.16 - lz-string: 1.4.4 - pretty-format: 27.5.1 - dev: true - /@testing-library/dom@8.19.0: resolution: {integrity: sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==} engines: {node: '>=12'} @@ -8664,21 +8653,7 @@ packages: aria-query: 5.3.0 chalk: 4.1.2 dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - pretty-format: 27.5.1 - dev: true - - /@testing-library/dom@9.3.1: - resolution: {integrity: sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==} - engines: {node: '>=14'} - dependencies: - '@babel/code-frame': 7.22.13 - '@babel/runtime': 7.23.2 - '@types/aria-query': 5.0.1 - aria-query: 5.1.3 - chalk: 4.1.2 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 + lz-string: 1.4.4 pretty-format: 27.5.1 dev: true @@ -8758,7 +8733,7 @@ packages: react-dom: <18.0.0 dependencies: '@babel/runtime': 7.18.9 - '@testing-library/dom': 8.17.1 + '@testing-library/dom': 8.19.0 '@types/react-dom': 17.0.17 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -8772,7 +8747,7 @@ packages: react-dom: ^18.0.0 dependencies: '@babel/runtime': 7.18.9 - '@testing-library/dom': 8.17.1 + '@testing-library/dom': 8.19.0 '@types/react-dom': 18.0.6 react: 18.0.0 react-dom: 18.0.0(react@18.0.0) @@ -8786,7 +8761,7 @@ packages: react-dom: ^18.0.0 dependencies: '@babel/runtime': 7.18.9 - '@testing-library/dom': 8.17.1 + '@testing-library/dom': 8.19.0 '@types/react-dom': 18.0.6 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -8800,7 +8775,7 @@ packages: react-dom: ^18.0.0 dependencies: '@babel/runtime': 7.18.9 - '@testing-library/dom': 8.17.1 + '@testing-library/dom': 8.19.0 '@types/react-dom': 18.0.8 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -8826,18 +8801,18 @@ packages: peerDependencies: svelte: ^3 || ^4 dependencies: - '@testing-library/dom': 9.3.1 + '@testing-library/dom': 9.3.3 svelte: 4.1.1 dev: true - /@testing-library/user-event@13.5.0(@testing-library/dom@8.17.1): + /@testing-library/user-event@13.5.0(@testing-library/dom@8.19.0): resolution: {integrity: sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==} engines: {node: '>=10', npm: '>=6'} peerDependencies: '@testing-library/dom': '>=7.21.4' dependencies: '@babel/runtime': 7.23.2 - '@testing-library/dom': 8.17.1 + '@testing-library/dom': 8.19.0 dev: true /@testing-library/user-event@14.4.3(@testing-library/dom@9.3.3): @@ -8876,10 +8851,6 @@ packages: resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} dev: true - /@types/aria-query@5.0.1: - resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==} - dev: true - /@types/aria-query@5.0.3: resolution: {integrity: sha512-0Z6Tr7wjKJIk4OUEjVUQMtyunLDy339vcMaj38Kpj6jM2OE1p3S4kXExKZ7a3uXQAPCoy3sbrP1wibDKaf39oA==} dev: true diff --git a/test/ui/fixtures/console.test.ts b/test/ui/fixtures/console.test.ts new file mode 100644 index 000000000000..2550b9a32503 --- /dev/null +++ b/test/ui/fixtures/console.test.ts @@ -0,0 +1,33 @@ +/* eslint-disable no-console */ + +import { it } from "vitest"; +import { prettyDOM } from "@testing-library/dom" + +// https://github.com/vitest-dev/vitest/issues/2765 +it('regexp', () => { + console.log(/(?\w)/) +}) + +// https://github.com/vitest-dev/vitest/issues/3934 +it('html-raw', async () => { + console.log(` +
+ + + +
+`); +}) + +// https://github.com/vitest-dev/vitest/issues/1279 +it('html-pretty', () => { + const div = document.createElement("div"); + div.innerHTML = ` +
+ + + +
+ `.replaceAll(/\n */gm, ""); // strip new liens + console.log(prettyDOM(div)) +}) diff --git a/test/ui/package.json b/test/ui/package.json index f682c941bfea..4da03349c435 100644 --- a/test/ui/package.json +++ b/test/ui/package.json @@ -8,7 +8,8 @@ }, "devDependencies": { "@playwright/test": "^1.39.0", - "execa": "^6.1.0", + "@testing-library/dom": "^9.3.3", + "happy-dom": "latest", "vitest": "workspace:*" } } diff --git a/test/ui/test/html-report.spec.ts b/test/ui/test/html-report.spec.ts index d69579935a8e..062dd1f98796 100644 --- a/test/ui/test/html-report.spec.ts +++ b/test/ui/test/html-report.spec.ts @@ -32,7 +32,7 @@ test.describe('html report', () => { await page.goto(pageUrl) // dashbaord - await expect(page.locator('[aria-labelledby=tests]')).toContainText('1 Pass 0 Fail 1 Total') + await expect(page.locator('[aria-labelledby=tests]')).toContainText('4 Pass 0 Fail 4 Total') // report await page.getByText('sample.test.ts').click() diff --git a/test/ui/test/ui.spec.ts b/test/ui/test/ui.spec.ts index 7b5cb8bef691..69a3bdb73bb1 100644 --- a/test/ui/test/ui.spec.ts +++ b/test/ui/test/ui.spec.ts @@ -23,7 +23,7 @@ test.describe('ui', () => { await page.goto(pageUrl) // dashbaord - await expect(page.locator('[aria-labelledby=tests]')).toContainText('1 Pass 0 Fail 1 Total') + await expect(page.locator('[aria-labelledby=tests]')).toContainText('4 Pass 0 Fail 4 Total') // report await page.getByText('sample.test.ts').click() @@ -40,4 +40,11 @@ test.describe('ui', () => { expect(pageErrors).toEqual([]) }) + + test('console', async ({ page }) => { + await page.goto(pageUrl) + await page.getByText('fixtures/console.test.ts').click() + await page.getByTestId('btn-console').click() + await page.getByText('/(?\\w)/').click() + }) }) diff --git a/test/ui/vitest.config.ts b/test/ui/vitest.config.ts index bdd49afa080c..47a9163b7cbc 100644 --- a/test/ui/vitest.config.ts +++ b/test/ui/vitest.config.ts @@ -3,5 +3,6 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { dir: './fixtures', + environment: 'happy-dom', }, })