Add more Dialog tests

This commit is contained in:
Ryan Gossiaux
2021-12-26 18:08:03 -08:00
parent 08021bbf21
commit 9bd9901ef6
3 changed files with 233 additions and 4 deletions

View File

@@ -4,12 +4,13 @@
// This component is only for use in tests // This component is only for use in tests
export let initialOpen = false; export let initialOpen = false;
export let onClose = () => {}; export let onClose = () => {};
export let buttonInside = false;
export let buttonText: string | null = null; export let buttonText: string | null = null;
export let buttonProps = {}; export let buttonProps = {};
let state = initialOpen; let state = initialOpen;
</script> </script>
{#if buttonText !== null} {#if buttonText !== null && !buttonInside}
<button {...buttonProps} on:click={() => (state = !state)} <button {...buttonProps} on:click={() => (state = !state)}
>{buttonText}</button >{buttonText}</button
> >
@@ -20,5 +21,10 @@
on:close={(e) => (state = e.detail)} on:close={(e) => (state = e.detail)}
on:close={onClose} on:close={onClose}
> >
{#if buttonText !== null && buttonInside}
<button {...buttonProps} on:click={() => (state = !state)}
>{buttonText}</button
>
{/if}
<slot /> <slot />
</Dialog> </Dialog>

View File

@@ -5,9 +5,11 @@ import { suppressConsoleLogs } from "$lib/test-utils/suppress-console-logs";
import { render } from "@testing-library/svelte"; import { render } from "@testing-library/svelte";
import TestRenderer from "$lib/test-utils/TestRenderer.svelte"; import TestRenderer from "$lib/test-utils/TestRenderer.svelte";
import Button from "$lib/internal/elements/Button.svelte"; import Button from "$lib/internal/elements/Button.svelte";
import Div from "$lib/internal/elements/Div.svelte";
import Form from "$lib/internal/elements/Form.svelte";
import P from "$lib/internal/elements/P.svelte"; import P from "$lib/internal/elements/P.svelte";
import Input from "$lib/internal/elements/Input.svelte"; import Input from "$lib/internal/elements/Input.svelte";
import { assertDialog, assertDialogDescription, DialogState, getDialog } from "$lib/test-utils/accessibility-assertions"; import { assertActiveElement, assertDialog, assertDialogDescription, DialogState, getByText, getDialog, getDialogOverlay } from "$lib/test-utils/accessibility-assertions";
import { click, Keys, press } from "$lib/test-utils/interactions"; import { click, Keys, press } from "$lib/test-utils/interactions";
import Transition from "$lib/components/transitions/TransitionRoot.svelte"; import Transition from "$lib/components/transitions/TransitionRoot.svelte";
import { tick } from "svelte"; import { tick } from "svelte";
@@ -399,7 +401,7 @@ describe('Keyboard interactions', () => {
TestRenderer, { TestRenderer, {
allProps: [ allProps: [
[ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [ [ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [
["Contents"], "Contents",
[Input, { id: "name" }], [Input, { id: "name" }],
[TestTabSentinel], [TestTabSentinel],
]], ]],
@@ -432,7 +434,7 @@ describe('Keyboard interactions', () => {
TestRenderer, { TestRenderer, {
allProps: [ allProps: [
[ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [ [ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [
["Contents"], "Contents",
[Input, { id: "name", onKeydown: (e: CustomEvent) => { e.preventDefault(); e.stopPropagation(); } }], [Input, { id: "name", onKeydown: (e: CustomEvent) => { e.preventDefault(); e.stopPropagation(); } }],
[TestTabSentinel], [TestTabSentinel],
]], ]],
@@ -458,3 +460,220 @@ describe('Keyboard interactions', () => {
}) })
}) })
}) })
describe('Mouse interactions', () => {
it(
'should be possible to close a Dialog using a click on the Dialog.Overlay',
suppressConsoleLogs(async () => {
render(
TestRenderer, {
allProps: [
[ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [
[DialogOverlay],
"Contents",
[TestTabSentinel],
]],
]
})
// Open dialog
await click(document.getElementById('trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click to close
await click(getDialogOverlay())
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
})
)
it(
'should not close the Dialog when clicking on contents of the Dialog.Overlay',
suppressConsoleLogs(async () => {
render(
TestRenderer, {
allProps: [
[ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [
[DialogOverlay, {}, [
[Button, {}, "hi"]
]],
"Contents",
[TestTabSentinel],
]],
]
})
// Open dialog
await click(document.getElementById('trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click on an element inside the overlay
await click(getByText('hi'))
// Verify it is still open
assertDialog({ state: DialogState.Visible })
})
)
it(
'should be possible to close the dialog, and re-focus the button when we click outside on the body element',
suppressConsoleLogs(async () => {
render(
TestRenderer, {
allProps: [
[ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [
"Contents",
[TestTabSentinel],
]],
]
})
// Open dialog
await click(getByText('Trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click the body to close
await click(document.body)
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify the button is focused
assertActiveElement(getByText('Trigger'))
})
)
it(
'should be possible to close the dialog, and keep focus on the focusable element',
suppressConsoleLogs(async () => {
render(
TestRenderer, {
allProps: [
[Button, {}, "Hello"],
[ManagedDialog, { buttonText: "Trigger", buttonProps: { id: "trigger" } }, [
"Contents",
[TestTabSentinel],
]],
]
})
// Open dialog
await click(getByText('Trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click the button to close (outside click)
await click(getByText('Hello'))
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify the button is focused
assertActiveElement(getByText('Hello'))
})
)
it(
'should stop propagating click events when clicking on the Dialog.Overlay',
suppressConsoleLogs(async () => {
let wrapperFn = jest.fn()
render(
TestRenderer, {
allProps: [
[Div, { onClick: wrapperFn }, [
[ManagedDialog, { initialOpen: true }, [
"Contents",
[DialogOverlay],
[TestTabSentinel],
]],
]]
]
})
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
// Click the Dialog.Overlay to close the Dialog
await click(getDialogOverlay())
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
})
)
it(
'should be possible to submit a form inside a Dialog',
suppressConsoleLogs(async () => {
let submitFn = jest.fn()
render(
TestRenderer, {
allProps: [
[ManagedDialog, { initialOpen: true }, [
[Form, { onSubmit: submitFn }, [
[Input, { type: "hidden", value: "abc" }],
[Button, { type: "submit" }, "Submit"]
]],
[TestTabSentinel],
]],
]
})
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Submit the form
await click(getByText('Submit'))
// Verify that the submitFn function has been called
expect(submitFn).toHaveBeenCalledTimes(1)
})
)
it(
'should stop propagating click events when clicking on an element inside the Dialog',
suppressConsoleLogs(async () => {
let wrapperFn = jest.fn()
render(
TestRenderer, {
allProps: [
[Div, { onClick: wrapperFn }, [
[ManagedDialog, { initialOpen: true, buttonInside: true, buttonText: "Inside" }, [
"Contents",
[TestTabSentinel],
]],
]]
]
})
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
// Click the button inside the the Dialog
await click(getByText('Inside'))
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
})
)
})

View File

@@ -5,6 +5,7 @@
onClose?: HandlerType; onClose?: HandlerType;
onFocus?: HandlerType; onFocus?: HandlerType;
onKeydown?: HandlerType; onKeydown?: HandlerType;
onSubmit?: HandlerType;
} }
type SingleComponent = type SingleComponent =
| string | string
@@ -36,12 +37,14 @@
let onClose: HandlerType = () => {}; let onClose: HandlerType = () => {};
let onFocus: HandlerType = () => {}; let onFocus: HandlerType = () => {};
let onKeydown: HandlerType = () => {}; let onKeydown: HandlerType = () => {};
let onSubmit: HandlerType = () => {};
if (allProps && typeof allProps !== "string" && isSingleComponent(allProps)) { if (allProps && typeof allProps !== "string" && isSingleComponent(allProps)) {
({ ({
onChange = onChange, onChange = onChange,
onClose = onClose, onClose = onClose,
onFocus = onFocus, onFocus = onFocus,
onKeydown = onKeydown, onKeydown = onKeydown,
onSubmit = onSubmit,
...spreadProps ...spreadProps
} = allProps[1] || {}); } = allProps[1] || {});
} }
@@ -59,6 +62,7 @@
on:close={onClose} on:close={onClose}
on:focus={onFocus} on:focus={onFocus}
on:keydown={onKeydown} on:keydown={onKeydown}
on:submit={onSubmit}
> >
<svelte:self allProps={allProps[2]} /> <svelte:self allProps={allProps[2]} />
</svelte:component> </svelte:component>