test(popover): cover open/close state and aria wiring
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
import {
|
||||||
|
fireEvent,
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
} from '@testing-library/svelte';
|
||||||
|
import Harness from './PopoverHarness.svelte';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the popover content element (the [popover] ancestor of the test content).
|
||||||
|
*/
|
||||||
|
function getContent(): HTMLElement {
|
||||||
|
return screen.getByTestId('content').closest('[popover]') as HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Popover', () => {
|
||||||
|
it('renders the trigger with aria wiring, closed by default', () => {
|
||||||
|
render(Harness);
|
||||||
|
const trigger = screen.getByRole('button', { name: 'Open' });
|
||||||
|
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
||||||
|
expect(trigger).toHaveAttribute('aria-haspopup', 'dialog');
|
||||||
|
expect(trigger).toHaveAttribute('popovertarget');
|
||||||
|
expect(getContent()).toHaveAttribute('data-state', 'closed');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens via the popover toggle and syncs aria-expanded + data-state', async () => {
|
||||||
|
render(Harness);
|
||||||
|
const trigger = screen.getByRole('button', { name: 'Open' });
|
||||||
|
// jsdom does not auto-invoke popovertarget; call the API the browser would.
|
||||||
|
getContent().showPopover();
|
||||||
|
await Promise.resolve();
|
||||||
|
expect(getContent()).toHaveAttribute('data-state', 'open');
|
||||||
|
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens when the parent sets open=true (state -> browser)', async () => {
|
||||||
|
render(Harness, { open: true });
|
||||||
|
await Promise.resolve();
|
||||||
|
expect(getContent()).toHaveAttribute('data-state', 'open');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('close() hides the popover and resets aria-expanded', async () => {
|
||||||
|
render(Harness, { open: true });
|
||||||
|
await Promise.resolve();
|
||||||
|
const trigger = screen.getByRole('button', { name: 'Open' });
|
||||||
|
await fireEvent.click(screen.getByTestId('close'));
|
||||||
|
expect(getContent()).toHaveAttribute('data-state', 'closed');
|
||||||
|
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<!--
|
||||||
|
Component: PopoverHarness
|
||||||
|
Test-only fixture: renders Popover with a button trigger and simple content
|
||||||
|
exposing the close() callback.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import Popover from './Popover.svelte';
|
||||||
|
|
||||||
|
let { open = $bindable(false) }: { open?: boolean } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Popover bind:open>
|
||||||
|
{#snippet trigger(props)}
|
||||||
|
<button {...props}>Open</button>
|
||||||
|
{/snippet}
|
||||||
|
{#snippet children({ close })}
|
||||||
|
<div data-testid="content">
|
||||||
|
<button onclick={close} data-testid="close">Close</button>
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
</Popover>
|
||||||
Reference in New Issue
Block a user