1
1
<script setup lang="ts">
2
- import { unifiedDiff } from ' ../../composables/diff'
3
- import { openInEditor , shouldOpenInEditor } from ' ../../composables/error'
4
- import type { ErrorWithDiff , File , ParsedStack , Suite , Task } from ' #types'
5
- import { config } from ' ~/composables/client'
2
+ import type Convert from ' ansi-to-html'
3
+ import ViewReportError from ' ./ViewReportError.vue'
4
+ import type { ErrorWithDiff , File , Suite , Task } from ' #types'
6
5
import { isDark } from ' ~/composables/dark'
7
6
import { createAnsiToHtmlFilter } from ' ~/composables/error'
7
+ import { config } from ' ~/composables/client'
8
8
9
9
const props = defineProps <{
10
10
file? : File
@@ -18,7 +18,7 @@ function collectFailed(task: Task, level: number): LeveledTask[] {
18
18
if (task .result ?.state !== ' fail' )
19
19
return []
20
20
21
- if (task .type === ' test' || task .type === ' benchmark' )
21
+ if (task .type === ' test' || task .type === ' benchmark' || task . type === ' typecheck ' )
22
22
return [{ ... task , level }]
23
23
else
24
24
return [{ ... task , level }, ... task .tasks .flatMap (t => collectFailed (t , level + 1 ))]
@@ -33,29 +33,36 @@ function escapeHtml(unsafe: string) {
33
33
.replace (/ '/ g , ' '' )
34
34
}
35
35
36
+ function createHtmlError(filter : Convert , error : ErrorWithDiff ) {
37
+ let htmlError = ' '
38
+ if (error .message .includes (' \x1B ' ))
39
+ htmlError = ` <b>${error .nameStr || error .name }</b>: ${filter .toHtml (escapeHtml (error .message ))} `
40
+
41
+ const startStrWithX1B = error .stackStr ?.includes (' \x1B ' )
42
+ if (startStrWithX1B || error .stack ?.includes (' \x1B ' )) {
43
+ if (htmlError .length > 0 )
44
+ htmlError += filter .toHtml (escapeHtml ((startStrWithX1B ? error .stackStr : error .stack ) as string ))
45
+ else
46
+ htmlError = ` <b>${error .nameStr || error .name }</b>: ${error .message }${filter .toHtml (escapeHtml ((startStrWithX1B ? error .stackStr : error .stack ) as string ))} `
47
+ }
48
+
49
+ if (htmlError .length > 0 )
50
+ return htmlError
51
+ return null
52
+ }
53
+
36
54
function mapLeveledTaskStacks(dark : boolean , tasks : LeveledTask []) {
37
55
const filter = createAnsiToHtmlFilter (dark )
38
56
return tasks .map ((t ) => {
39
57
const result = t .result
40
- if (result ) {
41
- const error = result .error
42
- if (error ) {
43
- let htmlError = ' '
44
- if (error .message .includes (' \x1B ' ))
45
- htmlError = ` <b>${error .nameStr || error .name }</b>: ${filter .toHtml (escapeHtml (error .message ))} `
46
-
47
- const startStrWithX1B = error .stackStr ?.includes (' \x1B ' )
48
- if (startStrWithX1B || error .stack ?.includes (' \x1B ' )) {
49
- if (htmlError .length > 0 )
50
- htmlError += filter .toHtml (escapeHtml ((startStrWithX1B ? error .stackStr : error .stack ) as string ))
51
- else
52
- htmlError = ` <b>${error .nameStr || error .name }</b>: ${error .message }${filter .toHtml (escapeHtml ((startStrWithX1B ? error .stackStr : error .stack ) as string ))} `
53
- }
54
-
55
- if (htmlError .length > 0 )
56
- result .htmlError = htmlError
57
- }
58
- }
58
+ if (! result )
59
+ return t
60
+ const errors = result .errors
61
+ ?.map (error => createHtmlError (filter , error ))
62
+ .filter (error => error != null )
63
+ .join (' <br><br>' )
64
+ if (errors ?.length )
65
+ result .htmlError = errors
59
66
return t
60
67
})
61
68
}
@@ -64,7 +71,7 @@ const failed = computed(() => {
64
71
const file = props .file
65
72
const failedFlatMap = file ?.tasks ?.flatMap (t => collectFailed (t , 0 )) ?? []
66
73
const result = file ?.result
67
- const fileError = result ?.error
74
+ const fileError = result ?.errors ?.[ 0 ]
68
75
// we must check also if the test cannot compile
69
76
if (fileError ) {
70
77
// create a dummy one
@@ -81,24 +88,6 @@ const failed = computed(() => {
81
88
}
82
89
return failedFlatMap .length > 0 ? mapLeveledTaskStacks (isDark .value , failedFlatMap ) : failedFlatMap
83
90
})
84
-
85
- function relative(p : string ) {
86
- if (p .startsWith (config .value .root ))
87
- return p .slice (config .value .root .length )
88
- return p
89
- }
90
-
91
- interface Diff { error: NonNullable <Pick <ErrorWithDiff , ' expected' | ' actual' >> }
92
- type ResultWithDiff = Task [' result' ] & Diff
93
- function isDiffShowable(result ? : Task [' result' ]): result is ResultWithDiff {
94
- return result && result ?.error ?.expected && result ?.error ?.actual
95
- }
96
-
97
- function diff(result : ResultWithDiff ): string {
98
- return unifiedDiff (result .error .actual , result .error .expected , {
99
- outputTruncateLength: 80 ,
100
- })
101
- }
102
91
</script >
103
92
104
93
<template >
@@ -117,23 +106,15 @@ function diff(result: ResultWithDiff): string {
117
106
<div v-if =" task.result?.htmlError" class =" scrolls scrolls-rounded task-error" >
118
107
<pre v-html =" task.result.htmlError" />
119
108
</div >
120
- <div v-else-if =" task.result?.error" class =" scrolls scrolls-rounded task-error" >
121
- <pre ><b >{{ task.result.error.name || task.result.error.nameStr }}</b >: {{ task.result.error.message }}</pre >
122
- <div v-for =" (stack, i) of task.result.error.stacks" :key =" i" class =" op80 flex gap-x-2 items-center" data-testid =" stack" >
123
- <pre > - {{ relative(stack.file) }}:{{ stack.line }}:{{ stack.column }}</pre >
124
- <div
125
- v-if =" shouldOpenInEditor(stack.file, props.file?.name)"
126
- v-tooltip.bottom =" 'Open in Editor'"
127
- class =" i-carbon-launch c-red-600 dark:c-red-400 hover:cursor-pointer min-w-1em min-h-1em"
128
- tabindex =" 0"
129
- aria-label =" Open in Editor"
130
- @click.passive =" openInEditor(stack.file, stack.line, stack.column)"
131
- />
132
- </div >
133
- <pre v-if =" isDiffShowable(task.result)" >
134
- {{ `\n${diff(task.result)}` }}
135
- </pre >
136
- </div >
109
+ <template v-else-if =" task .result ?.errors " >
110
+ <ViewReportError
111
+ v-for =" (error, idx) of task.result.errors"
112
+ :key =" idx"
113
+ :error =" error"
114
+ :filename =" file?.name"
115
+ :root =" config.root"
116
+ />
117
+ </template >
137
118
</div >
138
119
</div >
139
120
</template >
0 commit comments