feat(integration): add image variants section and standardize code snippets
This commit is contained in:
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)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user