Skip to content

Commit 122ff32

Browse files
authored
feat(reporters): print import duration breakdown (#9105)
1 parent aca6471 commit 122ff32

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1972
-241
lines changed

docs/.vitepress/style/main.css

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,31 +37,37 @@ button:focus:not(:focus-visible) {
3737
html:not(.dark) .custom-block.tip code {
3838
color: var(--vitest-custom-block-tip-code-text) !important;
3939
}
40+
4041
html:not(.dark) .custom-block.info code {
4142
color: var(--vitest-custom-block-info-code-text) !important;
4243
}
44+
4345
.custom-block.tip a:hover,
44-
.vp-doc .custom-block.tip a:hover > code {
46+
.vp-doc .custom-block.tip a:hover>code {
4547
color: var(--vp-c-brand-1) !important;
4648
opacity: 1;
4749
}
50+
4851
.custom-block.info a:hover,
49-
.vp-doc .custom-block.info a:hover > code {
52+
.vp-doc .custom-block.info a:hover>code {
5053
color: var(--vp-c-brand-1) !important;
5154
opacity: 1;
5255
}
56+
5357
html:not(.dark) .custom-block.info a:hover,
54-
html:not(.dark) .vp-doc .custom-block.info a:hover > code {
58+
html:not(.dark) .vp-doc .custom-block.info a:hover>code {
5559
color: var(--vitest-custom-block-info-code-text) !important;
5660
opacity: 1;
5761
}
62+
5863
.custom-block.warning a:hover,
59-
.vp-doc .custom-block.warning a:hover > code {
64+
.vp-doc .custom-block.warning a:hover>code {
6065
color: var(--vp-c-warning-1) !important;
6166
opacity: 1;
6267
}
68+
6369
.custom-block.danger a:hover,
64-
.vp-doc .custom-block.danger a:hover > code {
70+
.vp-doc .custom-block.danger a:hover>code {
6571
color: var(--vp-c-danger-1) !important;
6672
opacity: 1;
6773
}
@@ -70,6 +76,7 @@ html:not(.dark) .vp-doc .custom-block.info a:hover > code {
7076
:not(.dark) .title-icon {
7177
opacity: 1 !important;
7278
}
79+
7380
.dark .title-icon {
7481
opacity: 0.67 !important;
7582
}
@@ -81,6 +88,7 @@ html:not(.dark) .vp-doc .custom-block.info a:hover > code {
8188
.vp-doc a {
8289
text-decoration-style: dotted;
8390
}
91+
8492
.custom-block a:focus,
8593
.custom-block a:active,
8694
.custom-block a:hover,
@@ -92,7 +100,8 @@ html:not(.dark) .vp-doc .custom-block.info a:hover > code {
92100
text-decoration: underline;
93101
}
94102

95-
.vp-doc th, .vp-doc td {
103+
.vp-doc th,
104+
.vp-doc td {
96105
padding: 6px 10px;
97106
border: 1px solid #8882;
98107
}
@@ -113,14 +122,17 @@ img.resizable-img {
113122
.VPTeamMembersItem.medium .profile .data .affiliation {
114123
min-height: unset;
115124
}
125+
116126
.VPTeamMembersItem.medium .profile .data .desc {
117127
min-height: unset;
118128
}
129+
119130
/* fix height ~ 2 lines of text: 3 cards per row */
120131
@media (min-width: 648px) {
121132
.VPTeamMembersItem.medium .profile .data .affiliation {
122133
min-height: 4rem;
123134
}
135+
124136
.VPTeamMembersItem.medium .profile .data .desc {
125137
min-height: 4rem;
126138
}
@@ -130,6 +142,7 @@ img.resizable-img {
130142
.VPTeamMembersItem.small .profile .data .affiliation {
131143
min-height: 3rem;
132144
}
145+
133146
.VPTeamMembersItem.small .profile .data .desc {
134147
min-height: 3rem;
135148
}
@@ -139,33 +152,40 @@ img.resizable-img {
139152
.VPTeamMembersItem.small .profile .data .affiliation {
140153
min-height: 4rem;
141154
}
155+
142156
.VPTeamMembersItem.small .profile .data .desc {
143157
min-height: 4rem;
144158
}
145159
}
160+
146161
/* fix height ~ 3 lines of text: 3 cards per row */
147162
@media (min-width: 815px) and (max-width: 875px) {
148163
.VPTeamMembersItem.small .profile .data .affiliation {
149164
min-height: 4rem;
150165
}
166+
151167
.VPTeamMembersItem.small .profile .data .desc {
152168
min-height: 4rem;
153169
}
154170
}
171+
155172
/* fix height ~ 3 lines of text: 2 cards per row */
156173
@media (max-width: 612px) {
157174
.VPTeamMembersItem.small .profile .data .affiliation {
158175
min-height: 4rem;
159176
}
177+
160178
.VPTeamMembersItem.small .profile .data .desc {
161179
min-height: 4rem;
162180
}
163181
}
182+
164183
/* fix height: one card per row */
165184
@media (max-width: 568px) {
166185
.VPTeamMembersItem.small .profile .data .affiliation {
167186
min-height: unset;
168187
}
188+
169189
.VPTeamMembersItem.small .profile .data .desc {
170190
min-height: unset;
171191
}
@@ -176,3 +196,30 @@ img.resizable-img {
176196
transition: background-color 0.5s;
177197
display: inline-block;
178198
}
199+
200+
/* credit goes to https://dylanatsmith.com/wrote/styling-the-kbd-element */
201+
html:not(.dark) kbd {
202+
--kbd-color-background: #f7f7f7;
203+
--kbd-color-border: #cbcccd;
204+
--kbd-color-text: #222325;
205+
}
206+
207+
kbd {
208+
--kbd-color-background: #898b90;
209+
--kbd-color-border: #3d3e42;
210+
--kbd-color-text: #222325;
211+
212+
background-color: var(--kbd-color-background);
213+
color: var(--kbd-color-text);
214+
border-radius: 0.25rem;
215+
border: 1px solid var(--kbd-color-border);
216+
box-shadow: 0 2px 0 1px var(--kbd-color-border);
217+
font-family: var(--font-family-sans-serif);
218+
font-size: 0.75em;
219+
line-height: 1;
220+
min-width: 0.75rem;
221+
text-align: center;
222+
padding: 2px 5px;
223+
position: relative;
224+
top: -1px;
225+
}

docs/api/advanced/plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ Define a generator that will be applied before hashing the cache key.
142142

143143
Use this to make sure Vitest generates correct hash. It is a good idea to define this function if your plugin can be registered with different options.
144144

145-
This is called only if [`experimental.fsModuleCache`](/config/experimental#fsmodulecache) is defined.
145+
This is called only if [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache) is defined.
146146

147147
```ts
148148
interface PluginOptions {

docs/api/advanced/test-module.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,7 @@ interface ImportDuration {
120120
totalTime: number
121121
}
122122
```
123+
124+
## viteEnvironment <Version type="experimental">4.0.15</Version> <Experimental /> {#viteenvironment}
125+
126+
This is a Vite's [`DevEnvironment`](https://vite.dev/guide/api-environment) that transforms all files inside of the test module.

docs/api/advanced/vitest.md

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ function getSeed(): number | null
564564

565565
Returns the seed, if tests are running in a random order.
566566

567-
## experimental_parseSpecification <Version>4.0.0</Version> <Badge type="warning">experimental</Badge> {#parsespecification}
567+
## experimental_parseSpecification <Version type="experimental">4.0.0</Version> <Experimental /> {#parsespecification}
568568

569569
```ts
570570
function experimental_parseSpecification(
@@ -595,7 +595,7 @@ Vitest will only collect tests defined in the file. It will never follow imports
595595
Vitest collects all `it`, `test`, `suite` and `describe` definitions even if they were not imported from the `vitest` entry point.
596596
:::
597597

598-
## experimental_parseSpecifications <Version>4.0.0</Version> <Badge type="warning">experimental</Badge> {#parsespecifications}
598+
## experimental_parseSpecifications <Version type="experimental">4.0.0</Version> <Experimental /> {#parsespecifications}
599599

600600
```ts
601601
function experimental_parseSpecifications(
@@ -608,10 +608,67 @@ function experimental_parseSpecifications(
608608

609609
This method will [collect tests](#parsespecification) from an array of specifications. By default, Vitest will run only `os.availableParallelism()` number of specifications at a time to reduce the potential performance degradation. You can specify a different number in a second argument.
610610

611-
## experimental_clearCache <Version type="experimental">4.0.11</Version> <Badge type="warning">experimental</Badge> {#clearcache}
611+
## experimental_clearCache <Version type="experimental">4.0.11</Version> <Experimental /> {#clearcache}
612612

613613
```ts
614614
function experimental_clearCache(): Promise<void>
615615
```
616616

617617
Deletes all Vitest caches, including [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache).
618+
619+
## experimental_getSourceModuleDiagnostic <Version type="experimental">4.0.15</Version> <Experimental /> {#getsourcemodulediagnostic}
620+
621+
```ts
622+
export function experimental_getSourceModuleDiagnostic(
623+
moduleId: string,
624+
testModule?: TestModule,
625+
): Promise<SourceModuleDiagnostic>
626+
```
627+
628+
::: details Types
629+
```ts
630+
export interface ModuleDefinitionLocation {
631+
line: number
632+
column: number
633+
}
634+
635+
export interface SourceModuleLocations {
636+
modules: ModuleDefinitionDiagnostic[]
637+
untracked: ModuleDefinitionDiagnostic[]
638+
}
639+
640+
export interface ModuleDefinitionDiagnostic {
641+
start: ModuleDefinitionLocation
642+
end: ModuleDefinitionLocation
643+
startIndex: number
644+
endIndex: number
645+
url: string
646+
resolvedId: string
647+
}
648+
649+
export interface ModuleDefinitionDurationsDiagnostic extends ModuleDefinitionDiagnostic {
650+
selfTime: number
651+
totalTime: number
652+
external?: boolean
653+
}
654+
655+
export interface UntrackedModuleDefinitionDiagnostic {
656+
url: string
657+
resolvedId: string
658+
selfTime: number
659+
totalTime: number
660+
external?: boolean
661+
}
662+
663+
export interface SourceModuleDiagnostic {
664+
modules: ModuleDefinitionDurationsDiagnostic[]
665+
untrackedModules: UntrackedModuleDefinitionDiagnostic[]
666+
}
667+
```
668+
:::
669+
670+
Returns module's diagnostic. If [`testModule`](/api/advanced/test-module) is not provided, `selfTime` and `totalTime` will be aggregated across all tests that were running the last time. If the module was not transformed or executed, the diagnostic will be empty.
671+
672+
::: warning
673+
At the moment, the [browser](/guide/browser/) modules are not supported.
674+
:::

docs/config/experimental.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,21 @@ export default defineConfig({
137137
::: warning
138138
It's important that Node can process `sdkPath` content because it is not transformed by Vitest. See [the guide](/guide/open-telemetry) on how to work with OpenTelemetry inside of Vitest.
139139
:::
140+
141+
## experimental.printImportBreakdown <Version type="experimental">4.0.15</Version> {#experimental-printimportbreakdown}
142+
143+
- **Type:** `boolean`
144+
- **Default:** `false`
145+
146+
Show import duration breakdown after tests have finished running. This option only works with [`default`](/guide/reporters#default), [`verbose`](/guide/reporters#verbose), or [`tree`](/guide/reporters#tree) reporters.
147+
148+
- Self: the time it took to import the module, excluding static imports;
149+
- Total: the time it took to import the module, including static imports. Note that this does not include `transform` time of the current module.
150+
151+
<img alt="An example of import breakdown in the terminal" src="/reporter-import-breakdown.png" />
152+
153+
Note that if the file path is too long, Vitest will truncate it at the start until it fits 45 character limit.
154+
155+
::: info
156+
[Vitest UI](/guide/ui#import-breakdown) shows a breakdown of imports automatically if at least one file took longer than 500 milliseconds to load. You can manually set this option to `false` to disable this.
157+
:::

docs/guide/open-telemetry.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ If enabled, Vitest integration generates spans that are scoped to your test's wo
88
OpenTelemetry initialization increases the startup time of every test unless Vitest runs without [isolation](/config/isolate). You can see it as the `vitest.runtime.traces` span inside `vitest.worker.start`.
99
:::
1010

11-
To start using OpenTelemetry in Vitest, specify an SDK module path via [`experimental.openTelemetry.sdkPath`](/config/experimental#opentelemetry) and set `experimental.openTelemetry.enabled` to `true`. Vitest will automatically instrument the whole process and each individual test worker.
11+
To start using OpenTelemetry in Vitest, specify an SDK module path via [`experimental.openTelemetry.sdkPath`](/config/experimental#experimental-opentelemetry) and set `experimental.openTelemetry.enabled` to `true`. Vitest will automatically instrument the whole process and each individual test worker.
1212

1313
Make sure to export the SDK as a default export, so that Vitest can flush the network requests before the process is closed. Note that Vitest doesn't automatically call `start`.
1414

docs/guide/ui.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,92 @@ npx vite preview --outDir ./html
5252

5353
You can configure output with [`outputFile`](/config/#outputfile) config option. You need to specify `.html` path there. For example, `./html/index.html` is the default value.
5454
:::
55+
56+
## Module Graph
57+
58+
Module Graph's tab displays the module graph of the selected test file.
59+
60+
::: info
61+
All of the provided images use [Zammad](https://github.com/zammad/zammad) repository as an example.
62+
:::
63+
64+
<img alt="The module graph view" img-light src="/ui/light-module-graph.png">
65+
<img alt="The module graph view" img-dark src="/ui/dark-module-graph.png">
66+
67+
If there are more than 50 modules, the module graph displays only the first two levels of the graph to reduce the visual clutter. You can always click on "Show Full Graph" icon to preview the full graph.
68+
69+
<center>
70+
<img alt="The 'Show Full Graph' button located close to the legend" img-light src="/ui/light-ui-show-graph.png">
71+
<img alt="The 'Show Full Graph' button located close to the legend" img-dark src="/ui/dark-ui-show-graph.png">
72+
</center>
73+
74+
::: warning
75+
Note that if your graph is too big, it may take some time before the node positions are stabilized.
76+
:::
77+
78+
You can always restore the entry module graph by clicking on "Reset". To expand the module graph, right-click or hold <kbd>Shift</kbd> while clicking the node that interests you. It will display all nodes related to the selected one.
79+
80+
By default, Vitest doesn't show the modules from `node_modules`. Usually, these modules are externalized. You can enable them by deselecting "Hide node_modules".
81+
82+
### Module Info
83+
84+
By left-clicking on the module node, you open the Module Info view.
85+
86+
<img alt="The module info view for an inlined module" img-light src="/ui/light-module-info.png">
87+
<img alt="The module info view for an inlined module" img-dark src="/ui/dark-module-info.png">
88+
89+
This view is separated into two parts. The top part shows the full module ID and some diagnostics about the module. If [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache) is enabled, there will be a "cached" or "not cached" badge. On the right you can see time diagnostics:
90+
91+
- Self Time: the time it took to import the module, excluding static imports.
92+
- Total Time: the time it took to import the module, including static imports. Note that this does not include `transform` time of the current module.
93+
- Transform: the time it took to transform the module.
94+
95+
If you opened this view by clicking on an import, you will also see a "Back" button at the start that will take you to the previous module.
96+
97+
The bottom part depends on the module type. If the module is external, you will only see the source code of that file. You will not be able to traverse the module graph any further, and you won't see how long it took to import static imports.
98+
99+
<img alt="The module info view for an external module" img-light src="/ui/light-module-info-external.png">
100+
<img alt="The module info view for an external module" img-dark src="/ui/dark-module-info-external.png">
101+
102+
If the module was inlined, you will see three more windows:
103+
104+
- Source: unchanged source code of the module
105+
- Transformed: the transformed code that Vitest executes using Vite's [module runner](https://vite.dev/guide/api-environment-runtimes#modulerunner)
106+
- Source Map (v3): source map mappings
107+
108+
All static imports in the "Source" window show a total time it took to evaluate them by the current module. If the import was already evaluated in the module graph, it will show `0ms` because it is cached by that point.
109+
110+
If the module took longer than 500 milliseconds to load, the time will be displayed in red. If the module took longer than 100 milliseconds, the time will be displayed in orange.
111+
112+
You can click on an import source to jump into that module and traverse the graph further (note `./support/assertions/index.ts` below).
113+
114+
<img alt="The module info view for an internal module" img-light src="/ui/light-module-info-traverse.png">
115+
<img alt="The module info view for an internal module" img-dark src="/ui/dark-module-info-traverse.png">
116+
117+
::: warning
118+
Note that type-only imports are not executed at runtime and do not display a total duration. They also cannot be opened.
119+
:::
120+
121+
If another plugin injects a module import during transformation, those imports will be displayed at the start of the module in gray colour (for example, modules injected by `import.meta.glob`). They also show the total time and can be traversed further.
122+
123+
<img alt="The module info view for an internal module" img-light src="/ui/light-module-info-shadow.png">
124+
<img alt="The module info view for an internal module" img-dark src="/ui/dark-module-info-shadow.png">
125+
126+
::: tip
127+
If you are developing a custom integration on top of Vitest, you can use [`vitest.experimental_getSourceModuleDiagnostic`](/api/advanced/vitest#getsourcemodulediagnostic) to retrieve this information.
128+
:::
129+
130+
### Import Breakdown
131+
132+
The Module Graph tab also provides an Import Breakdown with a list of modules that take the longest time to load (top 10 by default, but you can press "Show more" to load 10 more), sorted by Total Time.
133+
134+
<img alt="Import breakdown with a list of top 10 modules that take the longest time to load" img-light src="/ui/light-import-breakdown.png">
135+
<img alt="Import breakdown with a list of top 10 modules that take the longest time to load" img-dark src="/ui/dark-import-breakdown.png">
136+
137+
You can click on the module to see the Module Info. If the module is external, it will have the yellow color (the same color in the module graph).
138+
139+
The breakdown shows a list of modules with self time, total time, and a percentage relative to the time it took to load the whole test file.
140+
141+
The "Show Import Breakdown" icon will have a red color if there is at least one file that took longer than 500 milliseconds to load, and it will be orange if there is at least one file that took longer than 100 milliseconds.
142+
143+
By default, Vitest shows the breakdown automatically if there is at least one module that took longer than 500 milliseconds to load. You can control the behaviour by setting the [`experimental.printImportBreakdown`](/config/experimental#experimental-printimportbreakdown) option.
187 KB
Loading
323 KB
Loading
282 KB
Loading

0 commit comments

Comments
 (0)