Skip to content

Commit

Permalink
feat(ui): replace navigation tree with test explorer (#5907)
Browse files Browse the repository at this point in the history
  • Loading branch information
userquin authored Jun 20, 2024
1 parent 486fd11 commit 45dfc95
Show file tree
Hide file tree
Showing 34 changed files with 2,221 additions and 733 deletions.
16 changes: 0 additions & 16 deletions packages/ui/client/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,6 @@ declare global {
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const extendRef: typeof import('@vueuse/core')['extendRef']
const filesFailed: typeof import('./composables/summary')['filesFailed']
const filesIgnore: typeof import('./composables/summary')['filesIgnore']
const filesRunning: typeof import('./composables/summary')['filesRunning']
const filesSkipped: typeof import('./composables/summary')['filesSkipped']
const filesSnapshotFailed: typeof import('./composables/summary')['filesSnapshotFailed']
const filesSuccess: typeof import('./composables/summary')['filesSuccess']
const filesTodo: typeof import('./composables/summary')['filesTodo']
const finished: typeof import('./composables/summary')['finished']
const getCurrentBrowserIframe: typeof import('./composables/api')['getCurrentBrowserIframe']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
Expand Down Expand Up @@ -128,22 +120,14 @@ declare global {
const syncRef: typeof import('@vueuse/core')['syncRef']
const syncRefs: typeof import('@vueuse/core')['syncRefs']
const templateRef: typeof import('@vueuse/core')['templateRef']
const tests: typeof import('./composables/summary')['tests']
const testsFailed: typeof import('./composables/summary')['testsFailed']
const testsIgnore: typeof import('./composables/summary')['testsIgnore']
const testsSkipped: typeof import('./composables/summary')['testsSkipped']
const testsSuccess: typeof import('./composables/summary')['testsSuccess']
const testsTodo: typeof import('./composables/summary')['testsTodo']
const throttledRef: typeof import('@vueuse/core')['throttledRef']
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
const time: typeof import('./composables/summary')['time']
const toRaw: typeof import('vue')['toRaw']
const toReactive: typeof import('@vueuse/core')['toReactive']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const toggleDark: typeof import('./composables/dark')['toggleDark']
const totalTests: typeof import('./composables/summary')['totalTests']
const triggerRef: typeof import('vue')['triggerRef']
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/client/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ declare module 'vue' {
DashboardEntry: typeof import('./components/dashboard/DashboardEntry.vue')['default']
DetailsPanel: typeof import('./components/DetailsPanel.vue')['default']
ErrorEntry: typeof import('./components/dashboard/ErrorEntry.vue')['default']
Explorer: typeof import('./components/explorer/Explorer.vue')['default']
ExplorerItem: typeof import('./components/explorer/ExplorerItem.vue')['default']
FileDetails: typeof import('./components/FileDetails.vue')['default']
FilterStatus: typeof import('./components/FilterStatus.vue')['default']
IconAction: typeof import('./components/IconAction.vue')['default']
IconButton: typeof import('./components/IconButton.vue')['default']
Modal: typeof import('./components/Modal.vue')['default']
Expand All @@ -25,9 +28,6 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
StatusIcon: typeof import('./components/StatusIcon.vue')['default']
TaskItem: typeof import('./components/TaskItem.vue')['default']
TasksList: typeof import('./components/TasksList.vue')['default']
TaskTree: typeof import('./components/TaskTree.vue')['default']
TestFilesEntry: typeof import('./components/dashboard/TestFilesEntry.vue')['default']
TestsEntry: typeof import('./components/dashboard/TestsEntry.vue')['default']
TestsFilesContainer: typeof import('./components/dashboard/TestsFilesContainer.vue')['default']
Expand Down
33 changes: 33 additions & 0 deletions packages/ui/client/components/FilterStatus.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
defineProps<{ label: string }>()
const modelValue = defineModel<boolean | null>()
</script>

<template>
<label
class="font-light text-sm checkbox flex items-center cursor-pointer py-1 text-sm w-full gap-y-1 mb-1px"
v-bind="$attrs"
@click.prevent="modelValue = !modelValue"
>
<span
:class="[
modelValue ? 'i-carbon:checkbox-checked-filled' : 'i-carbon:checkbox',
]"
text-lg
aria-hidden="true"
/>
<input
v-model="modelValue"
type="checkbox"
sr-only
>
<span flex-1 ms-2 select-none>{{ label }}</span>
</label>
</template>

<style>
.checkbox:focus-within {
outline: none;
@apply focus-base border-b-1 !mb-none;
}
</style>
2 changes: 1 addition & 1 deletion packages/ui/client/components/IconButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ defineProps<{
class="w-1.4em h-1.4em flex" :class="[{ 'bg-gray-500:35 op100': active }]"
>
<slot>
<div :class="icon" ma />
<span :class="icon" ma block />
</slot>
</button>
</template>
67 changes: 26 additions & 41 deletions packages/ui/client/components/Navigation.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script setup lang="ts">
import { hasFailedSnapshot } from '@vitest/ws-client'
import { Tooltip as VueTooltip } from 'floating-vue'
import type { File, Task } from 'vitest'
import {
Expand All @@ -9,22 +8,20 @@ import {
currentModule,
dashboardVisible,
disableCoverage,
openedTreeItems,
showCoverage,
showDashboard,
} from '~/composables/navigation'
import { client, files, findById, isReport, runAll } from '~/composables/client'
import { client, findById, isReport, runAll, runFiles } from '~/composables/client'
import { isDark, toggleDark } from '~/composables'
import { activeFileId } from '~/composables/params'
import { explorerTree } from '~/composables/explorer'
import { initialized, shouldShowExpandAll } from '~/composables/explorer/state'
const failedSnapshot = computed(
() => files.value && hasFailedSnapshot(files.value),
)
function updateSnapshot() {
return client.rpc.updateSnapshot()
}
const toggleMode = computed(() => (isDark.value ? 'light' : 'dark'))
const toggleMode = computed(() => isDark.value ? 'light' : 'dark')
function onItemClick(task: Task) {
activeFileId.value = task.file.id
Expand All @@ -41,46 +38,42 @@ async function onRunAll(files?: File[]) {
await nextTick()
}
}
await runAll(files)
if (files?.length) {
await runFiles(files)
}
else {
await runAll()
}
}
function collapseTests() {
openedTreeItems.value = []
explorerTree.collapseAllNodes()
}
function expandTests() {
files.value.forEach((file) => {
if (!openedTreeItems.value.includes(file.id)) {
openedTreeItems.value.push(file.id)
}
})
explorerTree.expandAllNodes()
}
</script>

<template>
<!-- TODO: have test tree so the folders are also nested: test -> filename -> suite -> test -->
<TasksList
border="r base"
:tasks="files"
:on-item-click="onItemClick"
:group-by-type="true"
:nested="true"
@run="onRunAll"
>
<template #header="{ filteredTests }">
<Explorer border="r base" :on-item-click="onItemClick" :nested="true" @run="onRunAll">
<template #header="{ filteredFiles }">
<img w-6 h-6 src="/favicon.svg" alt="Vitest logo">
<span font-light text-sm flex-1>Vitest</span>
<div class="flex text-lg">
<IconButton
v-show="openedTreeItems.length > 0"
v-show="!shouldShowExpandAll"
v-tooltip.bottom="'Collapse tests'"
title="Collapse tests"
:disabled="!initialized"
icon="i-carbon:collapse-all"
@click="collapseTests()"
/>
<IconButton
v-show="openedTreeItems.length === 0"
v-show="shouldShowExpandAll"
v-tooltip.bottom="'Expand tests'"
:disabled="!initialized"
title="Expand tests"
icon="i-carbon:expand-all"
@click="expandTests()"
Expand All @@ -101,10 +94,7 @@ function expandTests() {
>
<div class="i-carbon:folder-off ma" />
<template #popper>
<div
class="op100 gap-1 p-y-1"
grid="~ items-center cols-[1.5em_1fr]"
>
<div class="op100 gap-1 p-y-1" grid="~ items-center cols-[1.5em_1fr]">
<div class="i-carbon:information-square w-1.5em h-1.5em" />
<div>Coverage enabled but missing html reporter.</div>
<div style="grid-column: 2">
Expand All @@ -125,23 +115,18 @@ function expandTests() {
@click="showCoverage()"
/>
<IconButton
v-if="failedSnapshot && !isReport"
v-if="(explorerTree.summary.failedSnapshot && !isReport)"
v-tooltip.bottom="'Update all failed snapshot(s)'"
icon="i-carbon:result-old"
@click="updateSnapshot()"
:disabled="!explorerTree.summary.failedSnapshotEnabled"
@click="explorerTree.summary.failedSnapshotEnabled && updateSnapshot()"
/>
<IconButton
v-if="!isReport"
v-tooltip.bottom="
filteredTests
? filteredTests.length === 0
? 'No test to run (clear filter)'
: 'Rerun filtered'
: 'Rerun all'
"
:disabled="filteredTests?.length === 0"
v-tooltip.bottom="filteredFiles ? (filteredFiles.length === 0 ? 'No test to run (clear filter)' : 'Rerun filtered') : 'Rerun all'"
:disabled="filteredFiles?.length === 0"
icon="i-carbon:play"
@click="onRunAll(filteredTests)"
@click="onRunAll(filteredFiles)"
/>
<IconButton
v-tooltip.bottom="`Toggle to ${toggleMode} mode`"
Expand All @@ -150,5 +135,5 @@ function expandTests() {
/>
</div>
</template>
</TasksList>
</Explorer>
</template>
27 changes: 12 additions & 15 deletions packages/ui/client/components/ProgressBar.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup lang="ts">
import { files } from '~/composables/client'
import { filesFailed, filesSuccess, finished } from '~/composables/summary'
import { explorerTree } from '~/composables/explorer'
import { finished } from '~/composables/client/state'
const { width } = useWindowSize()
const classes = computed(() => {
// if there is no files, then in progress and gray
if (files.value.length === 0) {
// if there are no files, then in progress and gray
if (explorerTree.summary.files === 0) {
return '!bg-gray-4 !dark:bg-gray-7 in-progress'
}
else if (!finished.value) {
Expand All @@ -14,25 +14,22 @@ const classes = computed(() => {
return null
})
const total = computed(() => files.value.length)
const pass = computed(() => filesSuccess.value.length)
const failed = computed(() => filesFailed.value.length)
const widthPass = computed(() => {
const t = unref(total)
return t > 0 ? (width.value * pass.value) / t : 0
const t = explorerTree.summary.files
return t > 0 ? (width.value * explorerTree.summary.filesSuccess / t) : 0
})
const widthFailed = computed(() => {
const t = unref(total)
return t > 0 ? (width.value * failed.value) / t : 0
const t = explorerTree.summary.files
return t > 0 ? (width.value * explorerTree.summary.filesFailed / t) : 0
})
const pending = computed(() => {
const t = unref(total)
return t - failed.value - pass.value
const t = explorerTree.summary.files
return t - explorerTree.summary.filesFailed - explorerTree.summary.filesSuccess
})
const widthPending = computed(() => {
const t = unref(total)
return t > 0 ? (width.value * pending.value) / t : 0
const t = explorerTree.summary.files
return t > 0 ? (width.value * pending.value / t) : 0
})
</script>

Expand Down
Loading

0 comments on commit 45dfc95

Please sign in to comment.