diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/__snapshots__/index.js.snap b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/__snapshots__/index.js.snap
index f08a738cdcaedf..7e0c60c0954683 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/__snapshots__/index.js.snap
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/__snapshots__/index.js.snap
@@ -26,11 +26,12 @@ exports[`NavigationToggle when in full screen mode should display a default site
Toggle navigation
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js
index 159a48b2d7989e..5e832532911173 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { render, screen } from '@testing-library/react';
+import { render, screen, waitFor } from '@testing-library/react';
/**
* WordPress dependencies
@@ -24,9 +24,59 @@ jest.mock( '@wordpress/data/src/components/use-dispatch', () => ( {
jest.mock( '@wordpress/core-data' );
+/**
+ * Whether the element has been positioned.
+ * True if `top` and `left` have been set, false otherwise.
+ *
+ * @param {Element} element Element to check.
+ * @return {boolean} True if positioned, false otherwise.
+ */
+function isElementPositioned( element ) {
+ const { getComputedStyle } = element.ownerDocument.defaultView;
+
+ const { top, left } = getComputedStyle( element );
+ return top !== '' && left !== '';
+}
+
+/**
+ * Custom jest matcher.
+ * Determines whether an element has been positioned or not.
+ *
+ * @param {Element} element Element to check.
+ * @return {Object} Matcher result
+ */
+function toBePositioned( element ) {
+ const isInDocument =
+ element.ownerDocument === element.getRootNode( { composed: true } );
+ const isPositioned = isInDocument && isElementPositioned( element );
+ return {
+ pass: isPositioned,
+ message: () => {
+ const is = isPositioned ? 'is' : 'is not';
+ return [
+ this.utils.matcherHint(
+ `${ this.isNot ? '.not' : '' }.toBePositioned`,
+ 'element',
+ ''
+ ),
+ '',
+ `Received element ${ is } positioned${
+ isInDocument ? '' : ' (element is not in the document)'
+ }:`,
+ ` ${ this.utils.printReceived( element.cloneNode( false ) ) }`,
+ ].join( '\n' );
+ },
+ };
+}
+
+// Register the custom matcher
+expect.extend( {
+ toBePositioned,
+} );
+
describe( 'NavigationToggle', () => {
describe( 'when in full screen mode', () => {
- it( 'should display a user uploaded site icon if it exists', () => {
+ it( 'should display a user uploaded site icon if it exists', async () => {
useSelect.mockImplementation( ( cb ) => {
return cb( () => ( {
getCurrentTemplateNavigationPanelSubMenu: () => 'root',
@@ -40,12 +90,23 @@ describe( 'NavigationToggle', () => {
render(
);
+ // The `NavigationToggle` component auto-focuses on mount, and that
+ // causes the button tooltip to appear and to be positioned relative
+ // to the button. It happens async and we need to wait for it.
+ await waitFor(
+ () =>
+ expect(
+ screen.getByText( 'Toggle navigation' ).parentElement
+ ).toBePositioned(),
+ { interval: 10 } // It takes many microtask tick to position the popover.
+ );
+
const siteIcon = screen.getByAltText( 'Site Icon' );
expect( siteIcon ).toBeVisible();
} );
- it( 'should display a default site icon if no user uploaded site icon exists', () => {
+ it( 'should display a default site icon if no user uploaded site icon exists', async () => {
useSelect.mockImplementation( ( cb ) => {
return cb( () => ( {
getCurrentTemplateNavigationPanelSubMenu: () => 'root',
@@ -59,6 +120,15 @@ describe( 'NavigationToggle', () => {
const { container } = render(
);
+ // wait for the button tooltip to appear and to be positioned
+ await waitFor(
+ () =>
+ expect(
+ screen.getByText( 'Toggle navigation' ).parentElement
+ ).toBePositioned(),
+ { interval: 10 } // It takes many microtask tick to position the popover.
+ );
+
expect(
screen.queryByAltText( 'Site Icon' )
).not.toBeInTheDocument();