62 lines
2.9 KiB
TypeScript
62 lines
2.9 KiB
TypeScript
import { expect, it } from 'vitest';
|
|
import { render } from 'svelte/server';
|
|
import FormControls from '../fixtures/FormControls.svelte';
|
|
import Select from '../../src/lib/ui/components/primitives/Select.svelte';
|
|
|
|
it('preserves native constraints and combines field help with explicit descriptions', () => {
|
|
const body = render(FormControls).body;
|
|
const count = body.match(/<input[^>]*id="count"[^>]*>/)?.[0] ?? '';
|
|
expect(count).toContain('type="number"');
|
|
expect(count).toContain('min="1"');
|
|
expect(count).toContain('max="5"');
|
|
expect(count).toContain('step="1"');
|
|
expect(count).toContain('required');
|
|
expect(count).toContain('value="3"');
|
|
const descriptions = count.match(/aria-describedby="([^"]+)"/)?.[1].split(' ') ?? [];
|
|
expect(descriptions).toHaveLength(2);
|
|
for (const id of descriptions) expect(body).toContain(`id="${id}"`);
|
|
expect(descriptions).toContain('count-extra');
|
|
const password = body.match(/<input[^>]*id="password"[^>]*>/)?.[0] ?? '';
|
|
expect(password).toContain('minlength="8"');
|
|
expect(password).toContain('maxlength="128"');
|
|
expect(password).toContain('autocomplete="new-password"');
|
|
expect(password).toContain('aria-invalid="true"');
|
|
const errorId = password.match(/aria-describedby="([^"]+)"/)?.[1];
|
|
expect(body).toContain(`id="${errorId}"`);
|
|
const standalone = body.match(/<input[^>]*aria-label="Standalone search"[^>]*>/)?.[0] ?? '';
|
|
expect(standalone).not.toContain('aria-labelledby');
|
|
});
|
|
|
|
it('renders typed child options, groups and the shared chevron with the selected value', () => {
|
|
const body = render(FormControls).body;
|
|
expect(body).toMatch(/<option[^>]*value="false"[^>]*selected[^>]*>Oldest<\/option>/);
|
|
expect(body).toMatch(/<option[^>]*disabled[^>]*selected[^>]*>Choose a version<\/option>/);
|
|
expect(body).toContain('<optgroup label="Published">');
|
|
expect(body.match(/aria-hidden="true">▾/g)).toHaveLength(2);
|
|
});
|
|
|
|
it('retains the options API, placeholders and explicitly supplied accessibility attributes', () => {
|
|
const body = render(Select<number>, {
|
|
props: {
|
|
value: 2,
|
|
options: [
|
|
{ value: 1, label: 'One', disabled: true },
|
|
{ value: 2, label: 'Two' }
|
|
],
|
|
placeholder: 'Choose',
|
|
disabled: true,
|
|
name: 'quantity',
|
|
'aria-label': 'Quantity',
|
|
'aria-describedby': 'quantity-help',
|
|
'aria-invalid': true
|
|
}
|
|
}).body;
|
|
expect(body).toMatch(/<option value="" disabled[^>]*>Choose<\/option>/);
|
|
expect(body).toMatch(/<option[^>]*value="1"[^>]*disabled[^>]*>One<\/option>/);
|
|
expect(body).toMatch(/<option[^>]*value="2"[^>]*selected[^>]*>Two<\/option>/);
|
|
expect(body).toContain('aria-label="Quantity"');
|
|
expect(body).toContain('aria-describedby="quantity-help"');
|
|
expect(body).toContain('aria-invalid="true"');
|
|
expect(body).toMatch(/<select[^>]*disabled/);
|
|
});
|