import type { RunnerTestFile } from 'vitest' import { faker } from '@faker-js/faker' import { beforeEach, describe, expect, it } from 'vitest' import { config } from '~/composables/client' import { page, render } from '~/test' import ViewReport from './ViewReport.vue' config.value.root = '' const taskErrorTestId = 'task-error' const viewReportTestId = 'view-report' const stackRowTestId = 'stack' function makeTextStack() { return { line: faker.number.int({ min: 0, max: 120 }), column: faker.number.int({ min: 0, max: 5000 }), // Absolute file paths file: faker.system.filePath(), method: faker.hacker.verb(), } } // 5 Stacks const textStacks = Array.from({ length: 5 }, makeTextStack) const diff = ` \x1B[32m- Expected\x1B[39m \x1B[31m+ Received\x1B[39m \x1B[2m Object {\x1B[22m \x1B[2m "a": 1,\x1B[22m \x1B[32m- "b": 2,\x1B[39m \x1B[31m+ "b": 3,\x1B[39m \x1B[2m }\x1B[22m ` const error = { name: 'Do some test', stacks: textStacks, message: 'Error: Transform failed with 1 error:', diff, } const fileWithTextStacks: RunnerTestFile = { id: 'f-1', name: 'test/plain-stack-trace.ts', type: 'suite', mode: 'run', filepath: 'test/plain-stack-trace.ts', fullName: 'test/plain-stack-trace.ts', meta: {}, result: { state: 'fail', errors: [error], }, tasks: [], projectName: '', file: null!, } fileWithTextStacks.file = fileWithTextStacks describe('ViewReport', () => { describe('RunnerTestFile where stacks are in text', () => { beforeEach(() => { render(ViewReport, { props: { file: fileWithTextStacks, }, attrs: { 'data-testid': viewReportTestId, }, }) }) it('renders all of the stacks', () => { const stacks = error.stacks const stacksElements = page.getByTestId(stackRowTestId) expect(stacksElements).toHaveLength(stacks.length) for (let idx = 0; idx < stacks.length; idx++) { const { column, line, file: fileName } = stacks[idx] expect(stacksElements.nth(idx)).toHaveTextContent(`${line}:${column}`) expect(stacksElements.nth(idx)).toHaveTextContent(`- ${fileName}`) } }) it('renders the error message', () => { const report = page.getByTestId(viewReportTestId) expect(report).toHaveTextContent(error.message) expect(report).toHaveTextContent(error.name) }) }) it('test html stack trace without html message', () => { const file: RunnerTestFile = { id: 'f-1', name: 'test/plain-stack-trace.ts', type: 'suite', mode: 'run', filepath: 'test/plain-stack-trace.ts', fullName: 'test/plain-stack-trace.ts', meta: {}, result: { state: 'fail', errors: [ { name: 'Do some test', stacks: [], stack: '\x1B[33mtest/plain-stack-trace.ts\x1B[0m', message: 'Error: Transform failed with 1 error:', diff, }, ], }, tasks: [], projectName: '', file: null!, } file.file = file const container = render(ViewReport, { props: { file }, }) const taskError = container.getByTestId(taskErrorTestId) const preElements = taskError.element().querySelectorAll('pre') expect(preElements).toHaveLength(1) expect(preElements[0].textContent, 'error has the correct plain text').toBe( 'Do some test: Error: Transform failed with 1 error:test/plain-stack-trace.ts', ) expect( preElements[0].children, 'the pre container has the correct children', ).toHaveLength(2) const [bold, stack] = preElements[0].children expect(bold.tagName, 'error contains element').toBe('B') expect(bold.textContent, 'the error element is correct').toBe( 'Do some test', ) expect( stack.children, 'the stack children elements is correct', ).toHaveLength(0) expect(stack.innerHTML, 'stack has the correct message').toBe( 'test/plain-stack-trace.ts', ) expect( stack.getAttribute('style'), 'the stack has the correct text color', ).toBe('color:#A50') }) it('test html stack trace and message', () => { const file: RunnerTestFile = { id: 'f-1', name: 'test/plain-stack-trace.ts', type: 'suite', mode: 'run', filepath: 'test/plain-stack-trace.ts', fullName: 'test/plain-stack-trace.ts', meta: {}, result: { state: 'fail', errors: [ { name: 'Do some test', stack: '\x1B[33mtest/plain-stack-trace.ts\x1B[0m', stacks: [], message: '\x1B[44mError: Transform failed with 1 error:\x1B[0m', diff, }, ], }, tasks: [], projectName: '', file: null!, } file.file = file const container = render(ViewReport, { props: { file }, }) const taskError = container.getByTestId(taskErrorTestId) const preElements = taskError.element().querySelectorAll('pre') expect(preElements).toHaveLength(1) expect(preElements[0].textContent, 'error has the correct plain text').toBe( 'Do some test: Error: Transform failed with 1 error:test/plain-stack-trace.ts', ) expect( preElements[0].children, 'the pre container has the correct children', ).toHaveLength(3) const [bold, error, stack] = preElements[0].children expect(bold.tagName, 'error contains element').toBe('B') expect(bold.textContent, 'the error element is correct').toBe( 'Do some test', ) expect(error.innerHTML, 'the error has the correct message').toBe( 'Error: Transform failed with 1 error:', ) expect( error.getAttribute('style'), 'the error has the correct background color', ).toBe('background-color:#00A') expect( stack.children, 'the stack children elements is correct', ).toHaveLength(0) expect(stack.innerHTML, 'stack has the correct message').toBe( 'test/plain-stack-trace.ts', ) expect( stack.getAttribute('style'), 'the stack has the correct text color', ).toBe('color:#A50') }) it('test diff display', () => { const component = render(ViewReport, { props: { file: fileWithTextStacks, }, }) const diffElement = component.getByTestId('diff') expect(diffElement.getByText(/Expected/)).toBeInTheDocument() expect(diffElement.getByText(/Received/)).toBeInTheDocument() expect(diffElement.getByText(/\\x1B/)).not.toBeInTheDocument() }) })