Skip to content

Commit

Permalink
Added additional tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugos68 committed May 12, 2024
1 parent 87bdd1f commit 0c6b08c
Show file tree
Hide file tree
Showing 5 changed files with 336 additions and 21 deletions.
2 changes: 2 additions & 0 deletions src/docs/components/Navigation/Navigation.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import IconUseHover from 'lucide-svelte/icons/square-mouse-pointer';
import IconUseClick from 'lucide-svelte/icons/mouse-pointer-2';
import IconUseRole from 'lucide-svelte/icons/person-standing';
import IconUseDismiss from 'lucide-svelte/icons/circle-x';
import IconFloatingArrow from 'lucide-svelte/icons/triangle';
import IconUtils from 'lucide-svelte/icons/wand-sparkles';
// Components
Expand Down Expand Up @@ -45,6 +46,7 @@
{ icon: IconUseHover, href: '/api/use-hover', label: 'useHover' },
{ icon: IconUseClick, href: '/api/use-click', label: 'useClick' },
{ icon: IconUseRole, href: '/api/use-role', label: 'useRole' },
{ icon: IconUseDismiss, href: '/api/use-dismiss', label: 'useDismiss' },
{ icon: IconFloatingArrow, href: '/api/floating-arrow', label: 'Floating Arrow' },
{ icon: IconUtils, href: '/api/utilities', label: 'Utilities' },
],
Expand Down
237 changes: 216 additions & 21 deletions src/lib/hooks/useDismiss/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,239 @@
import { fireEvent, render, screen } from '@testing-library/svelte/svelte5';
import { describe, expect, it } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
import App from './App.test.svelte';

describe('useDismiss', () => {
it('dismisses on outside pointerdown', async () => {
render(App, { open: true });
describe('default', () => {
it('does dismiss on outside pointerdown', async () => {
render(App, { open: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();
expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);
await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does dismiss on `Escape` key press', async () => {
render(App, { open: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.keyDown(document, { key: 'Escape' });

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});
});

describe('enabled', () => {
it('does dismiss when set to `true`', async () => {
render(App, { open: true, enabled: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does not dismiss when set to `false`', async () => {
render(App, { open: true, enabled: false });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).toBeInTheDocument();
});
});

describe('escapeKey', () => {
it('does dismiss on `Escape` key press when set to `true`', async () => {
render(App, { open: true, escapeKey: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.keyDown(document, { key: 'Escape' });

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does not dismiss on `Escape` key press when set to `false`', async () => {
render(App, { open: true, escapeKey: false });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.keyDown(document, { key: 'Escape' });

expect(screen.queryByTestId('floating')).toBeInTheDocument();
});
});

describe('outsidePress', () => {
describe('boolean', () => {
it('does dismiss on outside press when set to `true`', async () => {
render(App, { open: true, outsidePress: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does not dismiss on outside press when set to `false`', async () => {
render(App, { open: true, outsidePress: false });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).toBeInTheDocument();
});
});
describe('function', () => {
it('does dismiss on outside press when the function returns `true`', async () => {
render(App, { open: true, outsidePress: () => true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does not dismiss on outside press when the function returns `false`', async () => {
render(App, { open: true, outsidePress: () => false });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).toBeInTheDocument();
});

it('passes the corresponding event as argument', async () => {
const outsidePress = vi.fn();
render(App, { open: true, outsidePress });

expect(outsidePress).not.toHaveBeenCalled();

const pointerdownEvent = new Event('pointerdown');

await fireEvent.pointerDown(document, { event: pointerdownEvent });

expect(outsidePress).toHaveBeenCalled();

expect(outsidePress.mock.calls[0][0]).toBe(pointerdownEvent);
});
});
});
it('dismisses on `Escape` key press', async () => {
render(App, { open: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();
describe('outsidePressEvent', () => {
it('does dismiss on outside `pointerdown` event when set to `pointerdown`', async () => {
render(App, { open: true, outsidePress: true, outsidePressEvent: 'pointerdown' });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(document);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

await fireEvent.keyDown(document, { key: 'Escape' });
it('does dismiss on outside `mousedown` event when set to `mousedown`', async () => {
render(App, { open: true, outsidePress: true, outsidePressEvent: 'mousedown' });

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.mouseDown(document);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does dismiss on outside `click` event when set to `click`', async () => {
render(App, { open: true, outsidePress: true, outsidePressEvent: 'click' });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.click(document);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});
});

it('dismisses on reference press', async () => {
render(App, { open: true, referencePress: true });
describe('referencePress', () => {
it('does dismiss on reference press when set to `true`', async () => {
render(App, { open: true, referencePress: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(screen.getByTestId('reference'));

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

expect(screen.queryByTestId('floating')).toBeInTheDocument();
it('does not dismiss on reference press when set to `false`', async () => {
render(App, { open: true, referencePress: false });

await fireEvent.pointerDown(screen.getByTestId('reference'));
expect(screen.queryByTestId('floating')).toBeInTheDocument();

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
await fireEvent.pointerDown(screen.getByTestId('reference'));

expect(screen.queryByTestId('floating')).toBeInTheDocument();
});
});

describe('referencePressEvent', () => {
it('does dismiss on reference `pointerdown` event when set to `pointerdown`', async () => {
render(App, { open: true, referencePress: true, referencePressEvent: 'pointerdown' });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.pointerDown(screen.getByTestId('reference'));

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does dismiss on reference `mousedown` event when set to `mousedown`', async () => {
render(App, { open: true, referencePress: true, referencePressEvent: 'mousedown' });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.mouseDown(screen.getByTestId('reference'));

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does dismiss on reference `click` event when set to `click`', async () => {
render(App, { open: true, referencePress: true, referencePressEvent: 'click' });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.click(screen.getByTestId('reference'));

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});
});

it('dismisses on ancestor scroll', async () => {
render(App, { open: true, ancestorScroll: true });
describe('ancestorScroll', () => {
it('does dismiss on ancestor scroll when set to `true`', async () => {
render(App, { open: true, ancestorScroll: true });

expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.scroll(window);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
});

it('does not dismiss on ancestor scroll when set to `false`', async () => {
render(App, { open: true, ancestorScroll: false });

expect(screen.queryByTestId('floating')).toBeInTheDocument();
expect(screen.queryByTestId('floating')).toBeInTheDocument();

await fireEvent.scroll(window);
await fireEvent.scroll(window);

expect(screen.queryByTestId('floating')).not.toBeInTheDocument();
expect(screen.queryByTestId('floating')).toBeInTheDocument();
});
});
});
36 changes: 36 additions & 0 deletions src/routes/(inner)/api/use-dismiss/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import CodeBlock from '$docs/components/CodeBlock/CodeBlock.svelte';
import ExampleRaw from './Example.svelte?raw';
import Table from '$docs/components/Table/Table.svelte';
import { tableOptions } from './data.js';
</script>

<div class="space-y-10">
<!-- Header -->
<header class="card card-gradient space-y-8">
<h1 class="h1"><span>useDismiss</span></h1>
<p>
Closes the floating element when a dismissal is requested — by default, when the user presses
the <kbd class="kbd">escape</kbd> key or outside of the floating element with their pointer.
</p>
<CodeBlock lang="ts" code={`import { useDismiss } from '@skeletonlabs/floating-ui-svelte';`} />
</header>
<!-- Usage -->
<section class="space-y-8">
<h2 class="h2">Usage</h2>
<CodeBlock code={ExampleRaw} lang="svelte" />
</section>
<!-- Table: Options -->
<section class="space-y-8">
<h2 class="h2">Options</h2>
<Table data={tableOptions} />
</section>
<!-- Compare -->
<section class="space-y-8">
<h2 class="h2">Compare</h2>
<!-- prettier-ignore -->
<p>
Compare to <a class="anchor" href="https://floating-ui.com/docs/useDismiss" target="_blank">Floating UI React</a>.
</p>
</section>
</div>
21 changes: 21 additions & 0 deletions src/routes/(inner)/api/use-dismiss/Example.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script lang="ts">
import { useFloating, useInteractions, useDismiss } from '@skeletonlabs/floating-ui-svelte';
const floating = useFloating();
const click = useDismiss(floating.context);
const interactions = useInteractions([click]);
</script>

<!-- Reference Element -->
<button bind:this={floating.elements.reference} {...interactions.getReferenceProps()}>
Reference
</button>

<!-- Floating Element -->
<div
bind:this={floating.elements.floating}
style={floating.floatingStyles}
{...interactions.getFloatingProps()}
>
Tooltip
</div>
61 changes: 61 additions & 0 deletions src/routes/(inner)/api/use-dismiss/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Hook: useDismiss

import type { TableData } from '$docs/types.js';

// Options
export const tableOptions: TableData[] = [
{
property: `enabled`,
description: `Whether the Hook is enabled, including all internal Effects and event handlers.`,
type: `boolean`,
default: `true`,
},
{
property: `escapeKey`,
description: `Whether to dismiss the floating element upon pressing the \`esc\` key.`,
type: `boolean`,
default: `true`,
},
{
property: `referencePress`,
description: `Whether to dismiss the floating element upon pressing the reference element. You likely want to ensure the \`move\` option in the \`useHover()\` Hook has been disabled when this is in use.`,
type: `boolean`,
default: `false`,
},
{
property: `referencePressEvent`,
description: `The type of event to use to determine a “press”.`,
type: `'pointerdown' | 'mousedown' | 'click'`,
default: `'pointerdown'`,
},
{
property: `outsidePress`,
description: `Whether to dismiss the floating element upon pressing outside of the floating element.`,
type: `boolean | ((event: MouseEvent) => boolean)`,
default: `true`,
},
{
property: `outsidePressEvent`,
description: `The type of event to use to determine an outside “press”.`,
type: `'pointerdown' | 'mousedown' | 'click'`,
default: `'pointerdown'`,
},
{
property: `ancestorScroll`,
description: `Whether to dismiss the floating element upon scrolling an overflow ancestor.`,
type: `boolean`,
default: `false`,
},
{
property: `bubbles`,
description: `Determines whether event listeners bubble upwards through a tree of floating elements.`,
type: `boolean | { escapeKey?: boolean; outsidePress?: boolean }`,
default: `undefined`,
},
{
property: `capture`,
description: `Determines whether to use capture phase event listeners.`,
type: `boolean | { escapeKey?: boolean; outsidePress?: boolean }`,
default: `undefined`,
},
];

0 comments on commit 0c6b08c

Please sign in to comment.