mirror of
https://github.com/hanzoai/vitest.git
synced 2026-09-24 17:04:25 +00:00
161 lines
5.1 KiB
TypeScript
161 lines
5.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { locators, userEvent } from 'vitest/browser'
|
|
import { page, render } from '~/test'
|
|
import VisualRegressionSlider from './VisualRegressionSlider.vue'
|
|
|
|
locators.extend({
|
|
// @ts-expect-error this gets used only in the first block which tests elements removed from the accessibility tree
|
|
getByCSS(selector: string) {
|
|
return selector
|
|
},
|
|
})
|
|
|
|
const reference = {
|
|
path: '/__reference.png',
|
|
width: 500,
|
|
height: 200,
|
|
}
|
|
|
|
const actual = {
|
|
path: '/__actual.png',
|
|
width: 500,
|
|
height: 200,
|
|
}
|
|
|
|
const containerLabel = 'Image comparison slider showing reference and actual screenshots'
|
|
const inputLabel = 'Adjust slider to compare reference and actual images'
|
|
|
|
describe('VisualRegressionSlider', () => {
|
|
it('renders both images with correct URLs', async () => {
|
|
await render(VisualRegressionSlider, {
|
|
props: {
|
|
reference,
|
|
actual,
|
|
},
|
|
})
|
|
|
|
// !!! images are hidden/removed from the accessibility tree, so we fall back to CSS selectors
|
|
|
|
// both image tags should be rendered and contain the path
|
|
// @ts-expect-error extended only for this block
|
|
const images = page.getByCSS('img')
|
|
const referenceImage = images.first()
|
|
const actualImage = images.last()
|
|
|
|
expect(images.all()).toHaveLength(2)
|
|
|
|
await expect.element(referenceImage).toHaveProperty(
|
|
'src',
|
|
expect.stringContaining(encodeURIComponent(reference.path)),
|
|
)
|
|
await expect.element(actualImage).toHaveProperty(
|
|
'src',
|
|
expect.stringContaining(encodeURIComponent(actual.path)),
|
|
)
|
|
|
|
// images should be wrapped in (hidden) containers with role presentation
|
|
// @ts-expect-error extended only for this block
|
|
const referenceContainer = page.getByCSS('div:has(> img)').first()
|
|
// @ts-expect-error extended only for this block
|
|
const actualContainer = page.getByCSS('div:has(> img)').last()
|
|
|
|
await expect.element(referenceContainer).toHaveAttribute('aria-hidden', 'true')
|
|
await expect.element(referenceContainer).toHaveAttribute('role', 'presentation')
|
|
|
|
await expect.element(actualContainer).toHaveAttribute('aria-hidden', 'true')
|
|
await expect.element(actualContainer).toHaveAttribute('role', 'presentation')
|
|
})
|
|
|
|
it('has accessible descriptions', async () => {
|
|
await render(VisualRegressionSlider, {
|
|
props: {
|
|
reference,
|
|
actual,
|
|
},
|
|
})
|
|
|
|
const container = page.getByLabelText(containerLabel)
|
|
const input = page.getByLabelText(inputLabel)
|
|
const status = page.getByRole(
|
|
'status',
|
|
{ hasText: 'Showing 50% reference, 50% actual' },
|
|
)
|
|
|
|
// container with accessible label should exist and contain input and status
|
|
await expect.element(container).toBeInTheDocument()
|
|
await expect.element(container).toContainElement(input)
|
|
await expect.element(container).toContainElement(status)
|
|
// split is an implementation detail, but in absence of VRT it's a best-effort approach to check it's working
|
|
await expect.element(container).toHaveStyle('--split: 50%')
|
|
|
|
// input with label should be an input and have an id
|
|
await expect.element(input).toBeInstanceOf(HTMLInputElement)
|
|
await expect.element(input).toHaveAttribute('id')
|
|
|
|
// status element should exist and be connected to the input
|
|
await expect.element(status).toBeInTheDocument()
|
|
await expect.element(status).toHaveAttribute(
|
|
'for',
|
|
input.element().getAttribute('id'),
|
|
)
|
|
})
|
|
|
|
it('has slider boundaries', async () => {
|
|
await render(VisualRegressionSlider, {
|
|
props: {
|
|
reference,
|
|
actual,
|
|
},
|
|
})
|
|
|
|
const input = page.getByLabelText(inputLabel)
|
|
|
|
await expect.element(input).toHaveAttribute('min', '0')
|
|
await expect.element(input).toHaveAttribute('max', '100')
|
|
await expect.element(input).toHaveAttribute('step', '0.1')
|
|
})
|
|
|
|
it('updates split percentage on slider movement', async () => {
|
|
await render(VisualRegressionSlider, {
|
|
props: {
|
|
reference,
|
|
actual,
|
|
},
|
|
})
|
|
|
|
const container = page.getByLabelText(containerLabel)
|
|
const input = page.getByLabelText(inputLabel)
|
|
const status = page.getByRole('status')
|
|
|
|
// initial state should be 50
|
|
await expect.element(input).toHaveValue('50')
|
|
await expect.element(container).toHaveStyle('--split: 50%')
|
|
|
|
// keyboard interaction
|
|
await userEvent.click(status)
|
|
await userEvent.tab()
|
|
await userEvent.keyboard('{ArrowRight>10/}')
|
|
await userEvent.click(status)
|
|
|
|
await expect.element(input).toHaveValue('51')
|
|
await expect.element(container).toHaveStyle('--split: 51%')
|
|
await expect.element(status).toHaveTextContent('Showing 51% reference, 49% actual')
|
|
|
|
// mouse interaction
|
|
await userEvent.click(
|
|
input,
|
|
{
|
|
position: {
|
|
x: 1,
|
|
y: input.element().getBoundingClientRect().height / 2,
|
|
},
|
|
},
|
|
)
|
|
await userEvent.click(status)
|
|
|
|
await expect.element(input).toHaveValue('0')
|
|
await expect.element(status).toHaveTextContent('Showing 0% reference, 100% actual')
|
|
await expect.element(container).toHaveStyle('--split: 0%')
|
|
})
|
|
})
|