Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 25 additions & 21 deletions packages/client/src/components/components/AppList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,34 @@ function frameLabel(frame: DevtoolsExtensionFrameDescriptor): string {
<template>
<div class="no-scrollbar h-full min-h-0 select-none overflow-auto">
<ul v-if="frames.length > 1" class="m-0 list-none border-b border-base p-2">
<li
v-for="frame in frames"
:key="frame.frameId"
class="selectable-item"
:class="{ active: activeFrameId === frame.frameId }"
:title="frame.url"
@click="selectFrame(frame.frameId)"
>
<span class="min-w-0 truncate">
{{ frameLabel(frame) }}
</span>
<li v-for="frame in frames" :key="frame.frameId">
<button
class="selectable-item w-full border-0 bg-transparent color-inherit text-left font-[inherit]"
:class="{ active: activeFrameId === frame.frameId }"
type="button"
:title="frame.url"
:aria-pressed="activeFrameId === frame.frameId"
@click="selectFrame(frame.frameId)"
>
<span class="min-w-0 truncate">
{{ frameLabel(frame) }}
</span>
</button>
</li>
</ul>
<ul class="m-0 list-none p-2">
<li
v-for="app in apps"
:key="app.id"
class="selectable-item"
:class="{ active: selectedAppId === app.id }"
@click="selectApp(app.id)"
>
<span class="min-w-0 truncate">
{{ app.name }}{{ app.version ? ` (${app.version})` : '' }}
</span>
<li v-for="app in apps" :key="app.id">
<button
class="selectable-item w-full border-0 bg-transparent color-inherit text-left font-[inherit]"
:class="{ active: selectedAppId === app.id }"
type="button"
:aria-pressed="selectedAppId === app.id"
@click="selectApp(app.id)"
>
<span class="min-w-0 truncate">
{{ app.name }}{{ app.version ? ` (${app.version})` : '' }}
</span>
</button>
</li>
</ul>
</div>
Expand Down
65 changes: 65 additions & 0 deletions tests/integration/client/app-list.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// @vitest-environment happy-dom

import { mount } from '@vue/test-utils'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'
import AppList from '../../../packages/client/src/components/components/AppList.vue'

const activeFrameId = ref('frame:top')
const selectedAppId = ref('app:one')
const selectApp = vi.fn()
const selectFrame = vi.fn()

vi.mock('../../../packages/client/src/composables/devtools-client', () => ({
useDevtoolsClient: () => ({
activeFrameId,
apps: ref([
{ id: 'app:one', name: 'First app', version: '3.5.0' },
{ id: 'app:two', name: 'Second app' },
]),
frames: ref([
{ frameId: 'frame:top', main: true },
{ frameId: 'frame:nested', url: 'https://example.com/nested' },
]),
selectApp,
selectFrame,
selectedAppId,
}),
}))

describe('AppList', () => {
beforeEach(() => {
activeFrameId.value = 'frame:top'
selectedAppId.value = 'app:one'
selectApp.mockClear()
selectFrame.mockClear()
})

it('exposes frame and app entries as focusable selection buttons', async () => {
const wrapper = mount(AppList, { attachTo: document.body })
const buttons = wrapper.findAll('button')

expect(buttons.map((button) => button.text())).toEqual([
'Top frame',
'example.com/nested',
'First app (3.5.0)',
'Second app',
])
expect(buttons.map((button) => button.attributes('aria-pressed'))).toEqual([
'true',
'false',
'true',
'false',
])

buttons[0]!.element.focus()
expect(document.activeElement).toBe(buttons[0]!.element)

await buttons[1]!.trigger('click')
await buttons[3]!.trigger('click')
expect(selectFrame).toHaveBeenCalledWith('frame:nested')
expect(selectApp).toHaveBeenCalledWith('app:two')

wrapper.unmount()
})
})