Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add e2e tests for the global inserter to the Nav Editor screen #34803

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8b4eadb
Scaffold out very basic interface
getdave Sep 14, 2021
91c11d2
Wire up store state and UI
getdave Sep 7, 2021
04a1008
Add inserter button to header toolbar
getdave Sep 7, 2021
080da88
Use correct classname
getdave Sep 7, 2021
ce85b36
Use optimal props on inserter toggle
getdave Sep 7, 2021
a248cf2
Allow global inserter to insert blocks at root level of Nav block
getdave Sep 7, 2021
ff8c787
Avoid displaying inserter if there are no blocks to insert
getdave Sep 7, 2021
cf3a33f
Hide previews as they don't provide much value here
getdave Sep 7, 2021
3338882
Refactor Inserter to dedicate component
getdave Sep 8, 2021
14f0e31
Remove hardcoded conditional
getdave Sep 8, 2021
a30ac83
Remove unwanted ref usage
getdave Sep 8, 2021
c867936
Add toggle button styles and remove close button on larger screens
getdave Sep 8, 2021
d721afb
Allow tools to show on mobile viewports
getdave Sep 8, 2021
88c5de6
Conditionalise render of sidebar
getdave Sep 14, 2021
21b9b0e
Only hide undo/redo on smaller viewports
getdave Sep 8, 2021
2c3793f
Simplify Navigation Block hook
getdave Sep 8, 2021
70354c8
Ensure global inserter always targets root nav block
getdave Sep 8, 2021
8d1d7c8
Ensure items always inserted at end if root nav block is selected
getdave Sep 9, 2021
497d830
Update to use correct exported variable name
getdave Sep 9, 2021
d28bdaf
Handle focus and tab trapping via hook
getdave Sep 9, 2021
020a9a2
Rename component to make it clear it's the inserter button
getdave Sep 10, 2021
2d68661
Simplify secondary sidebar
getdave Sep 14, 2021
119c6ce
Alter directory structure in order to improve portability of code
getdave Sep 10, 2021
7518cb5
Make insertion point logic explicit
getdave Sep 10, 2021
3002c38
Add docblocks to store
getdave Sep 10, 2021
197204c
Add selector state guard
getdave Sep 10, 2021
1136792
Implement Browse All on quick inserter.
getdave Sep 10, 2021
02124b0
Move constant outside component body
getdave Sep 14, 2021
1571d00
Add dep to useSelect
getdave Sep 14, 2021
ed0ba2a
Add another dep to useSelect
getdave Sep 14, 2021
7d98bcf
Remove ref
getdave Sep 14, 2021
09edddc
Sort out Prettier's mess
getdave Sep 14, 2021
b7da582
Rename Inserter Button to Inserter Toggle for clarity and consistency
getdave Sep 14, 2021
a63d3ce
Apply correct CSS naming convention
getdave Sep 14, 2021
8deabcb
Initial visibility and functionality tests for toggle
getdave Sep 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions packages/e2e-tests/specs/experiments/navigation-editor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import {
visitAdminPage,
} from '@wordpress/e2e-test-utils';
import { addQueryArgs } from '@wordpress/url';
/**
* External dependencies
*/
// eslint-disable-next-line no-restricted-imports
import { find } from 'puppeteer-testing-library';

/**
* Internal dependencies
Expand Down Expand Up @@ -590,10 +595,12 @@ describe( 'Navigation editor', () => {
}
}

// eslint-disable-next-line jest/no-disabled-tests
it.skip( 'should not prompt to confirm unsaved changes for the newly selected menu', async () => {
await assertIsDirty( false );
} );

// eslint-disable-next-line jest/no-disabled-tests
it.skip( 'should prompt to confirm unsaved changes when menu name is edited', async () => {
await page.type(
'.edit-navigation-name-editor__text-control input',
Expand All @@ -603,4 +610,115 @@ describe( 'Navigation editor', () => {
await assertIsDirty( true );
} );
} );

describe( 'Sidebar inserter', () => {
const initialMenu = {
id: 4,
description: '',
name: 'Main Menu',
slug: 'main-menu',
meta: [],
auto_add: false,
};

it( 'disables inserter toggle when Navigation block is in placeholder state', async () => {
await setUpResponseMocking( [
...getMenuMocks( {
GET: [ initialMenu ],
POST: initialMenu,
} ),
...getMenuItemMocks( { GET: [] } ),
] );

await visitNavigationEditor();

// Wait for the block to be present.
await expect( {
role: 'document',
name: 'Block: Navigation',
} ).toBeFound();

// Check for the placeholder state
await expect( {
role: 'button',
name: 'Start blank',
} ).toBeFound();

// Expect the block inserter to be disabled.
await expect( {
name: 'Toggle block inserter',
disabled: true,
role: 'button',
} ).toBeFound();
} );

it( 'enables inserter toggle when Navigation block is in editable state', async () => {
await setUpResponseMocking( [
...getMenuMocks( {
GET: [ initialMenu ],
POST: initialMenu,
} ),
...getMenuItemMocks( { GET: menuItemsFixture } ),
] );

await visitNavigationEditor();

// Wait for the block to be present.
await expect( {
role: 'document',
name: 'Block: Navigation',
} ).toBeFound();

// Expect the block inserter to be found.
await expect( {
name: 'Toggle block inserter',
role: 'button',
} ).toBeFound();

// Work around bug where `find` with `disabled=false` doesn't return anything.
const isEnabled = await page.$eval(
'[aria-label="Toggle block inserter"]',
( element ) => ! element.disabled
);

expect( isEnabled ).toBeTruthy();
} );

it( 'inserter toggle toggles the inserter sidebar open and closed', async () => {
await setUpResponseMocking( [
...getMenuMocks( {
GET: [ initialMenu ],
POST: initialMenu,
} ),
...getMenuItemMocks( { GET: menuItemsFixture } ),
] );

await visitNavigationEditor();

// Wait for the block to be present.
await expect( {
role: 'document',
name: 'Block: Navigation',
} ).toBeFound();

// Expect inserter sidebar to **not** be in the DOM.
await expect( {
role: 'region',
name: 'Block library',
} ).not.toBeFound();

const inserterToggle = await find( {
name: 'Toggle block inserter',
role: 'button',
} );

await inserterToggle.click();

// Expect the inserter sidebar to be present in the DOM.
await expect( {
role: 'region',
name: 'Block library',
} ).toBeFound();
} );
} );
} );
33 changes: 22 additions & 11 deletions packages/edit-navigation/src/components/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { decodeEntities } from '@wordpress/html-entities';
import SaveButton from './save-button';
import UndoButton from './undo-button';
import RedoButton from './redo-button';
import InserterToggle from './inserter-toggle';
import MenuSwitcher from '../menu-switcher';
import { useMenuEntityProp } from '../../hooks';

Expand All @@ -26,7 +27,9 @@ export default function Header( {
navigationPost,
} ) {
const isMediumViewport = useViewportMatch( 'medium' );

const [ menuName ] = useMenuEntityProp( 'name', selectedMenuId );

let actionHeaderText;

if ( menuName ) {
Expand All @@ -44,23 +47,31 @@ export default function Header( {

return (
<div className="edit-navigation-header">
{ isMediumViewport && (
<div className="edit-navigation-header__toolbar-wrapper">
<div className="edit-navigation-header__toolbar-wrapper">
{ isMediumViewport && (
<h1 className="edit-navigation-header__title">
{ __( 'Navigation' ) }
</h1>
<NavigableToolbar
className="edit-navigation-header__toolbar"
aria-label={ __( 'Document tools' ) }
>
<UndoButton />
<RedoButton />
</NavigableToolbar>
</div>
) }
) }

<NavigableToolbar
className="edit-navigation-header__toolbar"
aria-label={ __( 'Document tools' ) }
>
<InserterToggle />
{ isMediumViewport && (
<>
<UndoButton />
<RedoButton />
</>
) }
</NavigableToolbar>
</div>

<h2 className="edit-navigation-header__subtitle">
{ isMenuSelected && decodeEntities( actionHeaderText ) }
</h2>

{ isMenuSelected && (
<div className="edit-navigation-header__actions">
<DropdownMenu
Expand Down
57 changes: 57 additions & 0 deletions packages/edit-navigation/src/components/header/inserter-toggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* WordPress dependencies
*/
import { store as blockEditorStore } from '@wordpress/block-editor';
import { Button, ToolbarItem } from '@wordpress/components';
import { _x } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { plus } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { useNavigationEditorRootBlock } from '../../hooks';
import { store as editNavigationStore } from '../../store';

function InserterToggle() {
const { navBlockClientId } = useNavigationEditorRootBlock();

const { isInserterOpened, hasInserterItems } = useSelect(
( select ) => {
return {
hasInserterItems: select( blockEditorStore ).hasInserterItems(
navBlockClientId
),
isInserterOpened: select(
editNavigationStore
).isInserterOpened(),
};
},
[ navBlockClientId ]
);

const { setIsInserterOpened } = useDispatch( editNavigationStore );

return (
<ToolbarItem
as={ Button }
className="edit-navigation-header-inserter-toggle"
variant="primary"
isPressed={ isInserterOpened }
onMouseDown={ ( event ) => {
event.preventDefault();
} }
onClick={ () => setIsInserterOpened( ! isInserterOpened ) }
icon={ plus }
/* translators: button label text should, if possible, be under 16
characters. */
label={ _x(
'Toggle block inserter',
'Generic label for block inserter button'
) }
disabled={ ! hasInserterItems }
/>
);
}

export default InserterToggle;
31 changes: 31 additions & 0 deletions packages/edit-navigation/src/components/header/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,34 @@
display: none;
}
}


// INSERTER TOGGLE
.edit-navigation-header-inserter-toggle {

svg {
transition: transform cubic-bezier(0.165, 0.84, 0.44, 1) 0.2s;
@include reduce-motion("transition");
}

// Make the button appear like a "X" close button.
&.is-pressed {
svg {
transform: rotate(45deg);
}
}
}

// INSERTER PANEL
.edit-navigation-layout__inserter-panel-header {
padding-top: $grid-unit-10;
padding-right: $grid-unit-10;
display: flex;
justify-content: flex-end;

// Hide close button within panel on larger screens as this
// action is provided by the inserter toggle or ESC key.
@include break-medium() {
display: none;
}
}
95 changes: 95 additions & 0 deletions packages/edit-navigation/src/components/inserter-sidebar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* WordPress dependencies
*/
import { Button } from '@wordpress/components';
import { close } from '@wordpress/icons';
import {
__experimentalLibrary as Library,
store as blockEditorStore,
} from '@wordpress/block-editor';
import {
useViewportMatch,
__experimentalUseDialog as useDialog,
} from '@wordpress/compose';
import { useDispatch, useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as editNavigationStore } from '../../store';
import { useNavigationEditorRootBlock } from '../../hooks';

const SHOW_PREVIEWS = false;

function InserterSidebar() {
const isMobileViewport = useViewportMatch( 'medium', '<' );

const {
navBlockClientId,
lastNavBlockItemIndex,
} = useNavigationEditorRootBlock();

const { hasInserterItems, selectedBlockClientId } = useSelect(
( select ) => {
return {
hasInserterItems: select( blockEditorStore ).hasInserterItems(
navBlockClientId
),
selectedBlockClientId: select(
blockEditorStore
).getSelectedBlock()?.clientId,
};
},
[ navBlockClientId ]
);

const { setIsInserterOpened } = useDispatch( editNavigationStore );

const [ inserterDialogRef, inserterDialogProps ] = useDialog( {
onClose: () => setIsInserterOpened( false ),
} );

// Only concerned with whether there are items to display. If not then
// we shouldn't render.
if ( ! hasInserterItems ) {
return null;
}

const shouldInsertInNavBlock =
! selectedBlockClientId || navBlockClientId === selectedBlockClientId;

return (
<div
ref={ inserterDialogRef }
{ ...inserterDialogProps }
className="edit-navigation-layout__inserter-panel"
>
<div className="edit-navigation-layout__inserter-panel-header">
<Button
icon={ close }
onClick={ () => setIsInserterOpened( false ) }
/>
</div>
<div className="edit-navigation-layout__inserter-panel-content">
<Library
// If the root Nav block is selected then any items inserted by the
// global inserter should append after the last nav item. Otherwise
// simply allow default Gutenberg behaviour.
rootClientId={
shouldInsertInNavBlock ? navBlockClientId : undefined
} // If set, insertion will be into the block with this ID.
__experimentalInsertionIndex={
// If set, insertion will be into this explicit position.
shouldInsertInNavBlock
? lastNavBlockItemIndex
: undefined
}
shouldFocusBlock={ isMobileViewport }
showInserterHelpPanel={ SHOW_PREVIEWS }
/>
</div>
</div>
);
}

export default InserterSidebar;
Loading