Skip to content
Prev Previous commit
Next Next commit
Tests
  • Loading branch information
atomiks committed Dec 23, 2024
commit 88173bd47626028ae25f32a6675ed8d0234a8c9b
186 changes: 186 additions & 0 deletions packages/react/src/dialog/root/DialogRoot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { spy } from 'sinon';
import { act, fireEvent, screen, waitFor, describeSkipIf } from '@mui/internal-test-utils';
import { Dialog } from '@base-ui-components/react/dialog';
import { createRenderer } from '#test-utils';
import { Menu } from '@base-ui-components/react/menu';
import { Select } from '@base-ui-components/react/select';

const isJSDOM = /jsdom/.test(window.navigator.userAgent);

Expand Down Expand Up @@ -388,4 +390,188 @@ describe('<Dialog.Root />', () => {

expect(notifyTransitionEnd.callCount).to.equal(1);
});

describe('prop: modal', () => {
it('should render an internal backdrop when `true`', async () => {
Comment thread
atomiks marked this conversation as resolved.
const { user } = await render(
<div>
<Dialog.Root>
<Dialog.Trigger data-testid="trigger">Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Popup />
</Dialog.Portal>
</Dialog.Root>
<button>Outside</button>
</div>,
);

const trigger = screen.getByTestId('trigger');

await user.click(trigger);

await waitFor(() => {
expect(screen.queryByRole('dialog')).not.to.equal(null);
});

const popup = screen.getByRole('dialog');

// focus guard -> internal backdrop
// eslint-disable-next-line testing-library/no-node-access
expect(popup.previousElementSibling?.previousElementSibling).to.have.attribute(
'role',
'presentation',
);
});

it('should not render an internal backdrop when `false`', async () => {
const { user } = await render(
<div>
<Dialog.Root>
<Dialog.Trigger data-testid="trigger">Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Popup />
</Dialog.Portal>
</Dialog.Root>
<button>Outside</button>
</div>,
);

const trigger = screen.getByTestId('trigger');

await user.click(trigger);

await waitFor(() => {
expect(screen.queryByRole('dialog')).not.to.equal(null);
});

const popup = screen.getByRole('dialog');

// focus guard -> internal backdrop
// eslint-disable-next-line testing-library/no-node-access
expect(popup.previousElementSibling?.previousElementSibling).to.have.attribute(
'role',
'presentation',
);
});
});

describeSkipIf(isJSDOM)('nested popups', () => {
it('should not dismiss the dialog when dismissing outside a nested modal menu', async () => {
const { user } = await render(
<Dialog.Root>
<Dialog.Trigger>Open dialog</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Popup data-testid="dialog-popup">
<Menu.Root>
<Menu.Trigger>Open menu</Menu.Trigger>
<Menu.Portal>
<Menu.Positioner data-testid="menu-positioner">
<Menu.Popup>
<Menu.Item>Item</Menu.Item>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>,
);

const dialogTrigger = screen.getByRole('button', { name: 'Open dialog' });
await user.click(dialogTrigger);

await waitFor(() => {
expect(screen.queryByRole('dialog')).not.to.equal(null);
});

const menuTrigger = screen.getByRole('button', { name: 'Open menu' });

await user.click(menuTrigger);

await waitFor(() => {
expect(screen.queryByRole('menu')).not.to.equal(null);
});

const menuPositioner = screen.getByTestId('menu-positioner');
const menuInternalBackdrop = menuPositioner.previousElementSibling as HTMLElement;

await user.click(menuInternalBackdrop);

await waitFor(() => {
expect(screen.queryByRole('menu')).to.equal(null);
});
await waitFor(() => {
expect(screen.queryByRole('dialog')).not.to.equal(null);
});

const dialogPopup = screen.getByTestId('dialog-popup');
const dialogInternalBackdrop = dialogPopup.previousElementSibling
?.previousElementSibling as HTMLElement;

await user.click(dialogInternalBackdrop);

await waitFor(() => {
expect(screen.queryByRole('dialog')).to.equal(null);
});
});

it('should not dismiss the dialog when dismissing outside a nested select menu', async () => {
const { user } = await render(
<Dialog.Root>
<Dialog.Trigger>Open dialog</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Popup data-testid="dialog-popup">
<Select.Root>
<Select.Trigger data-testid="select-trigger">Open select</Select.Trigger>
<Select.Portal>
<Select.Positioner data-testid="select-positioner">
<Select.Popup>
<Select.Item>Item</Select.Item>
</Select.Popup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>,
);

const dialogTrigger = screen.getByRole('button', { name: 'Open dialog' });
await user.click(dialogTrigger);

await waitFor(() => {
expect(screen.queryByRole('dialog')).not.to.equal(null);
});

const selectTrigger = screen.getByTestId('select-trigger');

await user.click(selectTrigger);

await waitFor(() => {
expect(screen.queryByRole('listbox')).not.to.equal(null);
});

const selectPositioner = screen.getByTestId('select-positioner');
const selectInternalBackdrop = selectPositioner.previousElementSibling as HTMLElement;

await user.click(selectInternalBackdrop);

await waitFor(() => {
expect(screen.queryByRole('listbox')).to.equal(null);
});
await waitFor(() => {
expect(screen.queryByRole('dialog')).not.to.equal(null);
});

const dialogPopup = screen.getByTestId('dialog-popup');
const dialogInternalBackdrop = dialogPopup.previousElementSibling
?.previousElementSibling as HTMLElement;

await user.click(dialogInternalBackdrop);

await waitFor(() => {
expect(screen.queryByRole('dialog')).to.equal(null);
});
});
});
});
64 changes: 64 additions & 0 deletions packages/react/src/menu/root/MenuRoot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -788,4 +788,68 @@ describe('<Menu.Root />', () => {
expect(animationFinished).to.equal(true);
});
});

describe('prop: modal', () => {
it('should render an internal backdrop when `true`', async () => {
await render(
<div>
<Menu.Root>
<Menu.Trigger>Open</Menu.Trigger>
<Menu.Portal>
<Menu.Positioner data-testid="positioner">
<Menu.Popup>
<Menu.Item>1</Menu.Item>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
<button>Outside</button>
</div>,
);

const trigger = screen.getByRole('button', { name: 'Open' });

await user.click(trigger);

await waitFor(() => {
expect(screen.queryByRole('menu')).not.to.equal(null);
});

const positioner = screen.getByTestId('positioner');

// eslint-disable-next-line testing-library/no-node-access
expect(positioner.previousElementSibling).to.have.attribute('role', 'presentation');
});

it('should not render an internal backdrop when `false`', async () => {
await render(
<div>
<Menu.Root modal={false}>
<Menu.Trigger>Open</Menu.Trigger>
<Menu.Portal>
<Menu.Positioner data-testid="positioner">
<Menu.Popup>
<Menu.Item>1</Menu.Item>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
<button>Outside</button>
</div>,
);

const trigger = screen.getByRole('button', { name: 'Open' });

await user.click(trigger);

await waitFor(() => {
expect(screen.queryByRole('menu')).not.to.equal(null);
});

const positioner = screen.getByTestId('positioner');

// eslint-disable-next-line testing-library/no-node-access
expect(positioner.previousElementSibling).to.equal(null);
});
});
});
13 changes: 5 additions & 8 deletions packages/react/src/popover/root/PopoverRoot.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import * as React from 'react';
import { Popover } from '@base-ui-components/react/popover';
import { act, fireEvent, flushMicrotasks, screen, waitFor } from '@mui/internal-test-utils';
import userEvent from '@testing-library/user-event';
import { expect } from 'chai';
import { spy } from 'sinon';
import { createRenderer } from '#test-utils';
import { OPEN_DELAY } from '../utils/constants';

const user = userEvent.setup();

function Root(props: Popover.Root.Props) {
return <Popover.Root {...props} />;
}
Expand Down Expand Up @@ -200,7 +197,7 @@ describe('<Popover.Root />', () => {
);
}

await render(<Test />);
const { user } = await render(<Test />);

const closeButton = screen.getByText('Close');

Expand Down Expand Up @@ -261,7 +258,7 @@ describe('<Popover.Root />', () => {
);
}

await render(<Test />);
const { user } = await render(<Test />);

const closeButton = screen.getByText('Close');
await user.click(closeButton);
Expand Down Expand Up @@ -402,7 +399,7 @@ describe('<Popover.Root />', () => {

describe('focus management', () => {
it('focuses the trigger after the popover is closed but not unmounted', async () => {
await render(
const { user } = await render(
<div>
<input type="text" />
<Popover.Root>
Expand Down Expand Up @@ -435,7 +432,7 @@ describe('<Popover.Root />', () => {
});

it('does not move focus to the popover when opened with hover', async () => {
await render(
const { user } = await render(
<Popover.Root openOnHover delay={0}>
<Popover.Trigger>Toggle</Popover.Trigger>
<Popover.Positioner>
Expand Down Expand Up @@ -474,7 +471,7 @@ describe('<Popover.Root />', () => {
}
`;

await render(
const { user } = await render(
<div>
{/* eslint-disable-next-line react/no-danger */}
<style dangerouslySetInnerHTML={{ __html: style }} />
Expand Down
64 changes: 64 additions & 0 deletions packages/react/src/select/root/SelectRoot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,68 @@ describe('<Select.Root />', () => {
'',
);
});

describe('prop: modal', () => {
it('should render an internal backdrop when `true`', async () => {
const { user } = await render(
<div>
<Select.Root>
<Select.Trigger data-testid="trigger">Open</Select.Trigger>
<Select.Portal>
<Select.Positioner data-testid="positioner">
<Select.Popup>
<Select.Item>1</Select.Item>
</Select.Popup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<button>Outside</button>
</div>,
);

const trigger = screen.getByTestId('trigger');

await user.click(trigger);

await waitFor(() => {
expect(screen.queryByRole('listbox')).not.to.equal(null);
});

const positioner = screen.getByTestId('positioner');

// eslint-disable-next-line testing-library/no-node-access
expect(positioner.previousElementSibling).to.have.attribute('role', 'presentation');
});

it('should not render an internal backdrop when `false`', async () => {
const { user } = await render(
<div>
<Select.Root modal={false}>
<Select.Trigger data-testid="trigger">Open</Select.Trigger>
<Select.Portal>
<Select.Positioner data-testid="positioner">
<Select.Popup>
<Select.Item>1</Select.Item>
</Select.Popup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<button>Outside</button>
</div>,
);

const trigger = screen.getByTestId('trigger');

await user.click(trigger);

await waitFor(() => {
expect(screen.queryByRole('listbox')).not.to.equal(null);
});

const positioner = screen.getByTestId('positioner');

// eslint-disable-next-line testing-library/no-node-access
expect(positioner.previousElementSibling).to.equal(null);
});
});
});
Loading