Skip to content

Commit e83165e

Browse files
committed
feat(browser): add browser.detailsPanelPosition config option and button
1 parent db2d0b5 commit e83165e

23 files changed

Lines changed: 291 additions & 65 deletions

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Vitest is a next-generation testing framework powered by Vite. This is a monorep
100100
- Main docs in `docs/` directory
101101
- Built with `pnpm docs:build`
102102
- Local dev server: `pnpm docs`
103+
- When adding cli options, run `pnpm -C docs run cli-table` to update the cli-generated.md file
103104

104105
## Dependencies and Tools
105106

docs/.vitepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,10 @@ export default ({ mode }: { mode: string }) => {
644644
text: 'browser.ui',
645645
link: '/config/browser/ui',
646646
},
647+
{
648+
text: 'browser.detailsPanelPosition',
649+
link: '/config/browser/detailspanelposition',
650+
},
647651
{
648652
text: 'browser.viewport',
649653
link: '/config/browser/viewport',

docs/config/browser.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ List of available `browser` options:
9393
- [`browser.screenshotDirectory`](#browser-screenshotdirectory)
9494
- [`browser.screenshotFailures`](#browser-screenshotfailures)
9595
- [`browser.provider`](#browser-provider)
96+
- [`browser.detailsPanelPosition`](#browser-detailspanelposition)
9697

9798
Under the hood, Vitest transforms these instances into separate [test projects](/api/advanced/test-project) sharing a single Vite server for better caching performance.
9899

@@ -220,6 +221,14 @@ export interface BrowserProvider {
220221

221222
Should Vitest UI be injected into the page. By default, injects UI iframe during development.
222223

224+
## browser.detailsPanelPosition
225+
226+
- **Type:** `'right' | 'bottom'`
227+
- **Default:** `'right'`
228+
- **CLI:** `--browser.detailsPanelPosition=bottom`, `--browser.detailsPanelPosition=right`
229+
230+
Controls the default position of the details panel in the Vitest UI when running browser tests. See [`browser.detailsPanelPosition`](/config/browser/detailspanelposition) for more details.
231+
223232
## browser.viewport
224233

225234
- **Type:** `{ width, height }`
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
title: browser.detailsPanelPosition | Config
3+
outline: deep
4+
---
5+
6+
# browser.detailsPanelPosition
7+
8+
- **Type:** `'right' | 'bottom'`
9+
- **Default:** `'right'`
10+
- **CLI:** `--browser.detailsPanelPosition=bottom`, `--browser.detailsPanelPosition=right`
11+
12+
Controls the default position of the details panel in the Vitest UI when running browser tests.
13+
14+
- `'right'` - Shows the details panel on the right side with a horizontal split between the browser viewport and the details panel.
15+
- `'bottom'` - Shows the details panel at the bottom with a vertical split between the browser viewport and the details panel.
16+
17+
```ts [vitest.config.ts]
18+
import { defineConfig } from 'vitest/config'
19+
20+
export default defineConfig({
21+
test: {
22+
browser: {
23+
enabled: true,
24+
detailsPanelPosition: 'bottom', // or 'right'
25+
},
26+
},
27+
})
28+
```

docs/guide/cli-generated.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,13 @@ Run every browser test file in isolation. To disable isolation, use `--browser.i
346346

347347
Show Vitest UI when running tests (default: `!process.env.CI`)
348348

349+
### browser.detailsPanelPosition
350+
351+
- **CLI:** `--browser.detailsPanelPosition <position>`
352+
- **Config:** [browser.detailsPanelPosition](/config/browser/detailspanelposition)
353+
354+
Default position for the details panel in browser mode. Either `right` (horizontal split) or `bottom` (vertical split) (default: `right`)
355+
349356
### browser.fileParallelism
350357

351358
- **CLI:** `--browser.fileParallelism`

packages/ui/client/components/BrowserIframe.vue

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { computed } from 'vue'
55
import { viewport } from '~/composables/browser'
66
import { browserState } from '~/composables/client'
77
import {
8-
hideRightPanel,
8+
detailsPanelVisible,
9+
detailsPosition,
910
panels,
1011
showNavigationPanel,
11-
showRightPanel,
1212
updateBrowserPanel,
1313
} from '~/composables/navigation'
1414
import IconButton from './IconButton.vue'
@@ -86,19 +86,11 @@ const marginLeft = computed(() => {
8686
<div class="i-carbon-content-delivery-network" />
8787
<span pl-1 font-bold text-sm flex-auto ws-nowrap overflow-hidden truncate>Browser UI</span>
8888
<IconButton
89-
v-show="panels.details.main > 0"
90-
v-tooltip.bottom="'Hide Right Panel'"
91-
title="Hide Right Panel"
89+
v-show="detailsPosition === 'right' && !detailsPanelVisible"
90+
v-tooltip.bottom="'Show Details Panel'"
91+
title="Show Details Panel"
9292
icon="i-carbon:side-panel-close"
93-
rotate-180
94-
@click="hideRightPanel()"
95-
/>
96-
<IconButton
97-
v-show="panels.details.main === 0"
98-
v-tooltip.bottom="'Show Right Panel'"
99-
title="Show Right Panel"
100-
icon="i-carbon:side-panel-close"
101-
@click="showRightPanel()"
93+
@click="detailsPanelVisible = true"
10294
/>
10395
</div>
10496
<div p="l3 y2 r2" flex="~ gap-2" items-center bg-header border="b-2 base">
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script setup lang="ts">
2+
import DetailsHeaderButtons from '~/components/DetailsHeaderButtons.vue'
3+
</script>
4+
5+
<template>
6+
<div
7+
p="2"
8+
flex="~ gap-2"
9+
items-center
10+
bg-header
11+
border="b base"
12+
>
13+
<div flex-1 />
14+
<DetailsHeaderButtons />
15+
</div>
16+
</template>

packages/ui/client/components/Coverage.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<script setup lang="ts">
2+
import DetailsHeaderButtons from '~/components/DetailsHeaderButtons.vue'
3+
import { browserState } from '~/composables/client'
4+
25
defineProps<{
36
src: string
47
}>()
@@ -9,6 +12,7 @@ defineProps<{
912
<div p="3" h-10 flex="~ gap-2" items-center bg-header border="b base">
1013
<div class="i-carbon:folder-details-reference" />
1114
<span pl-1 font-bold text-sm flex-auto ws-nowrap overflow-hidden truncate>Coverage</span>
15+
<DetailsHeaderButtons v-if="browserState" />
1216
</div>
1317
<div flex-auto py-1 bg-white>
1418
<iframe id="vitest-ui-coverage" :src="src" />

packages/ui/client/components/Dashboard.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script setup lang="ts">
2+
import DetailsHeaderButtons from '~/components/DetailsHeaderButtons.vue'
3+
import { browserState } from '~/composables/client'
24
import TestsFilesContainer from './dashboard/TestsFilesContainer.vue'
35
</script>
46

@@ -7,6 +9,7 @@ import TestsFilesContainer from './dashboard/TestsFilesContainer.vue'
79
<div p="3" h-10 flex="~ gap-2" items-center bg-header border="b base">
810
<div class="i-carbon-dashboard" />
911
<span pl-1 font-bold text-sm flex-auto ws-nowrap overflow-hidden truncate>Dashboard</span>
12+
<DetailsHeaderButtons v-if="browserState" />
1013
</div>
1114
<div class="scrolls" flex-auto py-1>
1215
<TestsFilesContainer />
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<script setup lang="ts">
2+
import IconButton from '~/components/IconButton.vue'
3+
import {
4+
detailsPanelVisible,
5+
detailsPosition,
6+
hideDetailsPanel,
7+
showDetailsPanel,
8+
toggleDetailsPosition,
9+
} from '~/composables/navigation'
10+
11+
function getDetailsPanelToggleRotation(action: 'show' | 'hide') {
12+
// `i-carbon:side-panel-close` is treated as "pointing right" by default.
13+
// We rotate it based on where the details panel is positioned.
14+
if (detailsPosition.value === 'right') {
15+
return action === 'hide' ? 'rotate-180' : ''
16+
}
17+
// detailsPosition === 'bottom'
18+
return action === 'hide' ? '-rotate-90' : 'rotate-90'
19+
}
20+
</script>
21+
22+
<template>
23+
<IconButton
24+
v-tooltip.bottom="`Switch panel position (${detailsPosition === 'bottom' ? 'right' : 'bottom'})`"
25+
:title="`Switch panel position (${detailsPosition === 'bottom' ? 'right' : 'bottom'})`"
26+
icon="i-carbon-split-screen"
27+
:class="{ 'rotate-90': detailsPosition === 'right' }"
28+
@click="toggleDetailsPosition"
29+
/>
30+
<IconButton
31+
v-if="detailsPanelVisible"
32+
v-tooltip.bottom="detailsPosition === 'right' ? 'Hide Right Panel' : 'Hide Bottom Panel'"
33+
:title="detailsPosition === 'right' ? 'Hide Right Panel' : 'Hide Bottom Panel'"
34+
icon="i-carbon:side-panel-close"
35+
:class="getDetailsPanelToggleRotation('hide')"
36+
@click="hideDetailsPanel"
37+
/>
38+
<IconButton
39+
v-show="!detailsPanelVisible"
40+
v-tooltip.bottom="detailsPosition === 'right' ? 'Show Right Panel' : 'Show Bottom Panel'"
41+
:title="detailsPosition === 'right' ? 'Show Right Panel' : 'Show Bottom Panel'"
42+
icon="i-carbon:side-panel-close"
43+
:class="getDetailsPanelToggleRotation('show')"
44+
@click="showDetailsPanel"
45+
/>
46+
</template>

0 commit comments

Comments
 (0)