feat(integration): add image variants section and standardize code snippets

This commit is contained in:
Florian Sylvain committed 2026-10-12 23:27:41 +02:00
1 parent 6f9ae6207a
commit e6746f2be7
28 files changed
+2256 -422

No files matched your search

@@ -0,0 +1,132 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { flushPromises, mount, type VueWrapper } from '@vue/test-utils'
import uiPlugin from '@nuxt/ui/vue-plugin'
import UButton from '@nuxt/ui/components/Button.vue'
import CodeSnippet from '@/components/CodeSnippet.vue'
import type { CodeSnippetTab } from '@/lib/codeSnippet'
const THREE_TABS: CodeSnippetTab[] = [
{ k: 'curl', label: 'curl', code: 'curl -O "https://cms.renew.example/a"' },
{ k: 'html', label: 'HTML', code: '<img src="a">' },
{ k: 'js', label: 'JavaScript', code: 'const res = await fetch("a")' },
]
let wrapper: VueWrapper | null = null
function stubClipboard() {
const writeText = vi.fn().mockResolvedValue(undefined)
Object.defineProperty(navigator, 'clipboard', { configurable: true, value: { writeText } })
return writeText
}
function mountSnippet(tabs: CodeSnippetTab[] = THREE_TABS) {
wrapper = mount(CodeSnippet, {
props: { tabs },
attachTo: document.body,
global: { plugins: [uiPlugin] },
})
return wrapper
}
function copyButton(target: VueWrapper) {
return target.get('button[aria-label="Copy code"]')
}
afterEach(() => {
wrapper?.unmount()
wrapper = null
vi.useRealTimers()
document.body.innerHTML = ''
})
describe('CodeSnippet', () => {
it('renders three tabs, the first selected with an underline, and a Copy code button', () => {
const target = mountSnippet()
const list = target.get('[role="tablist"]')
expect(list.attributes('aria-label')).toBe('Language')
const tabs = list.findAll('[role="tab"]')
expect(tabs.map((tab) => tab.text())).toEqual(['curl', 'HTML', 'JavaScript'])
expect(tabs[0]!.attributes('aria-selected')).toBe('true')
expect(tabs[0]!.classes().join(' ')).toContain('shadow-')
expect(tabs[1]!.attributes('aria-selected')).toBe('false')
expect(tabs[1]!.classes().join(' ')).not.toContain('shadow-')
expect(copyButton(target).text()).toBe('Copy')
})
it('switches the pre on a tab click and copies the active tab', async () => {
const writeText = stubClipboard()
const target = mountSnippet()
expect(target.get('pre').text()).toBe(THREE_TABS[0]!.code)
await target.findAll('[role="tab"]')[2]!.trigger('click')
expect(target.get('pre').text()).toBe(THREE_TABS[2]!.code)
await copyButton(target).trigger('click')
expect(writeText).toHaveBeenCalledWith(THREE_TABS[2]!.code)
})
it('moves between tabs with the arrow keys', async () => {
const target = mountSnippet()
await target.findAll('[role="tab"]')[0]!.trigger('keydown', { key: 'ArrowRight' })
expect(target.get('pre').text()).toBe(THREE_TABS[1]!.code)
await target.findAll('[role="tab"]')[1]!.trigger('keydown', { key: 'ArrowLeft' })
expect(target.get('pre').text()).toBe(THREE_TABS[0]!.code)
})
it('renders a muted label and no tab for a single tab', () => {
const target = mountSnippet([
{ k: 'base', label: 'Base URL', code: 'https://cms.renew.example' },
])
expect(target.findAll('[role="tab"]')).toHaveLength(0)
expect(target.text()).toContain('Base URL')
expect(target.get('pre').text()).toBe('https://cms.renew.example')
})
it('copies, reads Copied in a polite region for 2 s, then reverts', async () => {
const writeText = stubClipboard()
vi.useFakeTimers()
const target = mountSnippet()
await copyButton(target).trigger('click')
await flushPromises()
expect(writeText).toHaveBeenCalledWith(THREE_TABS[0]!.code)
const region = target.get('[aria-live="polite"]')
expect(region.text()).toBe('Copied')
expect(target.findComponent(UButton).props('icon')).toBe('i-lucide-check')
await vi.advanceTimersByTimeAsync(1999)
expect(region.text()).toBe('Copied')
await vi.advanceTimersByTimeAsync(1)
expect(region.text()).toBe('Copy')
expect(target.findComponent(UButton).props('icon')).toBe('i-lucide-copy')
})
it('copies two instances independently', async () => {
stubClipboard()
const first = mountSnippet()
const second = mount(CodeSnippet, {
props: { tabs: THREE_TABS },
attachTo: document.body,
global: { plugins: [uiPlugin] },
})
await copyButton(first).trigger('click')
await flushPromises()
expect(copyButton(first).text()).toBe('Copied')
expect(copyButton(second).text()).toBe('Copy')
second.unmount()
})
it('draws a focusable pre without syntax markup', () => {
const target = mountSnippet()
const pre = target.get('pre')
expect(pre.attributes('tabindex')).toBe('0')
expect(pre.find('span').exists()).toBe(false)
})
})