UNPKG

@wordpress/block-library

Version:
603 lines (507 loc) 16.3 kB
/** * External dependencies */ import { act, selectRangeInRichText, typeInRichText, fireEvent, getEditorHtml, initializeEditor, waitFor, within, addBlock, getBlock, triggerBlockListLayout, } from 'test/helpers'; /** * WordPress dependencies */ import { getBlockTypes, unregisterBlockType } from '@wordpress/blocks'; import { registerCoreBlocks } from '@wordpress/block-library'; import { BACKSPACE, ENTER } from '@wordpress/keycodes'; describe( 'List block', () => { beforeAll( () => { // Register all core blocks registerCoreBlocks(); } ); afterAll( () => { // Clean up registered blocks getBlockTypes().forEach( ( block ) => { unregisterBlockType( block.name ); } ); } ); it( 'inserts block', async () => { const screen = await initializeEditor(); // Add block await addBlock( screen, 'List' ); // Get block const listBlock = await getBlock( screen, 'List' ); fireEvent.press( listBlock ); expect( listBlock ).toBeVisible(); // Trigger onLayout for the list await triggerBlockListLayout( listBlock ); // Get List item const listItemBlock = await getBlock( screen, 'List Item' ); fireEvent.press( listItemBlock ); expect( listItemBlock ).toBeVisible(); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'adds one item to the list', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li></li><!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); // Select List Item block const [ listItemBlock ] = screen.getAllByLabelText( /List Item Block\. Row 1/ ); fireEvent.press( listItemBlock ); const listItemField = within( listBlock ).getByPlaceholderText( 'List' ); typeInRichText( listItemField, 'First list item' ); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'shows different indentation levels', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>List item 1</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>List item 2<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>List item nested 1</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>List item nested 2<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Extra item 1</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Extra item 2</li> <!-- /wp:list-item --></ul> <!-- /wp:list --></li> <!-- /wp:list-item --></ul> <!-- /wp:list --></li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>List item 3</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); // Select List Item block const [ firstNestedLevelBlock ] = within( listBlock ).getAllByLabelText( /List Item Block\. Row 2/ ); fireEvent.press( firstNestedLevelBlock ); await triggerBlockListLayout( firstNestedLevelBlock ); // Select second level list const [ secondNestedLevelBlock ] = within( firstNestedLevelBlock ).getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( secondNestedLevelBlock ); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'changes the indentation level', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Item 1</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Item 2</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); // Select Second List Item block const [ listItemBlock ] = screen.getAllByLabelText( /List Item Block\. Row 2/ ); fireEvent.press( listItemBlock ); // Update indentation const indentButton = screen.getByLabelText( 'Indent' ); fireEvent.press( indentButton ); // Await recently indented list item layout const [ listItemBlock1 ] = screen.getAllByLabelText( /List Item Block\. Row 1/ ); await triggerBlockListLayout( listItemBlock1 ); // wait until inserter on the newly created indented block is enabled // this is slightly delayed (by updating block list settings) and would // trigger an "update not wrapped in act()" warning if not explicitly awaited. screen.findByRole( 'button', { name: 'Add block', disabled: false } ); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'removes the indentation level', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Item 1<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Item 2</li> <!-- /wp:list-item --></ul> <!-- /wp:list --></li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); // Select List Item block const [ firstNestedLevelBlock ] = within( listBlock ).getAllByLabelText( /List Item Block\. Row 1/ ); fireEvent.press( firstNestedLevelBlock ); await triggerBlockListLayout( firstNestedLevelBlock ); // Select Inner block List const [ innerBlockList ] = within( firstNestedLevelBlock ).getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( innerBlockList ); await triggerBlockListLayout( innerBlockList ); // Select nested List Item block const [ listItemBlock ] = within( innerBlockList ).getAllByLabelText( /List Item Block\. Row 1/ ); fireEvent.press( listItemBlock ); // Update indentation const outdentButton = screen.getByLabelText( 'Outdent' ); fireEvent.press( outdentButton ); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'changes to ordered list', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Item 1</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Item 2</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Item 3</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); // Update to ordered list const orderedButton = screen.getByLabelText( 'Ordered' ); fireEvent.press( orderedButton ); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'changes to reverse ordered list', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Item 1</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Item 2</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Item 3</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); // Update to ordered list const orderedButton = screen.getByLabelText( 'Ordered' ); fireEvent.press( orderedButton ); // Set order to reverse // Open block settings fireEvent.press( screen.getByLabelText( 'Open Settings' ) ); await waitFor( () => screen.getByTestId( 'block-settings-modal' ).props.isVisible ); const reverseButton = screen.getByLabelText( /Reverse order\. Off/ ); fireEvent.press( reverseButton ); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'sets a start value to an ordered list', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Item 1</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Item 2</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Item 3</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); // Update to ordered list const orderedButton = screen.getByLabelText( 'Ordered' ); fireEvent.press( orderedButton ); // Set order to reverse // Open block settings fireEvent.press( screen.getByLabelText( 'Open Settings' ) ); await waitFor( () => screen.getByTestId( 'block-settings-modal' ).props.isVisible ); const startValueButton = screen.getByLabelText( /Start value\. Empty/ ); fireEvent.press( startValueButton ); const startValueInput = within( startValueButton ).getByDisplayValue( '' ); fireEvent.changeText( startValueInput, '25' ); expect( getEditorHtml() ).toMatchSnapshot(); } ); it( 'splits empty list items into paragraphs', async () => { // Arrange const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One</li><!-- /wp:list-item --> <!-- wp:list-item --> <li>Two</li><!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml } ); // Act const listBlock = screen.getByLabelText( /List Block\. Row 1/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); const listItemField = screen.getByLabelText( /Text input. .*One.*/ ); selectRangeInRichText( listItemField, 3 ); fireEvent( listItemField, 'onKeyDown', { nativeEvent: {}, preventDefault() {}, keyCode: ENTER, } ); const listItemField2 = screen.getByLabelText( /Text input. Empty/ ); fireEvent( listItemField2, 'onKeyDown', { nativeEvent: {}, preventDefault() {}, keyCode: ENTER, } ); // Assert expect( getEditorHtml() ).toMatchInlineSnapshot( ` "<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One</li> <!-- /wp:list-item --></ul> <!-- /wp:list --> <!-- wp:paragraph --> <p></p> <!-- /wp:paragraph --> <!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Two</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->" ` ); } ); it( 'merges paragraphs into list items', async () => { const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One</li> <!-- /wp:list-item --></ul> <!-- /wp:list --> <!-- wp:paragraph --> <p>Two</p> <!-- /wp:paragraph --> <!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Three</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml } ); // Act const paragraphField = screen.getByLabelText( /Text input. .*Two.*/ ); selectRangeInRichText( paragraphField, 0 ); fireEvent( paragraphField, 'onKeyDown', { nativeEvent: {}, preventDefault() {}, keyCode: BACKSPACE, } ); // Assert expect( getEditorHtml() ).toMatchInlineSnapshot( ` "<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Two</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Three</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->" ` ); } ); it( 'merges lists into lists', async () => { // Arrange const initialHtml = `<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Two</li> <!-- /wp:list-item --></ul> <!-- /wp:list --> <!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Three</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml } ); // Act const listBlock = screen.getByLabelText( /List Block\. Row 2/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); const listItemField = screen.getByLabelText( /Text input\..*Three/ ); selectRangeInRichText( listItemField, 0 ); fireEvent( listItemField, 'onKeyDown', { nativeEvent: {}, preventDefault() {}, keyCode: BACKSPACE, } ); // Assert expect( getEditorHtml() ).toMatchInlineSnapshot( ` "<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Two</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Three</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->" ` ); } ); it( 'unwraps first item when attempting to merge with non-list block', async () => { const initialHtml = `<!-- wp:paragraph --> <p>A quick brown fox.</p> <!-- /wp:paragraph --> <!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One</li><!-- /wp:list-item --><!-- wp:list-item --> <li>Two</li><!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 2/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); // Select List Item block const [ listItemBlock ] = within( listBlock ).getAllByLabelText( /List Item Block\. Row 1/ ); fireEvent.press( listItemBlock ); // With cursor positioned at the beginning of the first List Item, press // backward delete const listItemField = within( listItemBlock ).getByLabelText( /Text input. .*One.*/ ); selectRangeInRichText( listItemField, 0 ); fireEvent( listItemField, 'onKeyDown', { nativeEvent: {}, preventDefault() {}, keyCode: BACKSPACE, } ); expect( getEditorHtml() ).toMatchInlineSnapshot( ` "<!-- wp:paragraph --> <p>A quick brown fox.</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>One</p> <!-- /wp:paragraph --> <!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Two</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->" ` ); } ); it( 'merges first item into its own paragraph block and keeps its nested items', async () => { const initialHtml = `<!-- wp:paragraph --> <p>A quick brown fox.</p> <!-- /wp:paragraph --> <!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>One<!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Two</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Three</li> <!-- /wp:list-item --></ul> <!-- /wp:list --></li> <!-- /wp:list-item --></ul> <!-- /wp:list -->`; const screen = await initializeEditor( { initialHtml, } ); // Select List block const [ listBlock ] = screen.getAllByLabelText( /List Block\. Row 2/ ); fireEvent.press( listBlock ); await triggerBlockListLayout( listBlock ); // Select List Item block const [ listItemBlock ] = within( listBlock ).getAllByLabelText( /List Item Block\. Row 1/ ); fireEvent.press( listItemBlock ); // With cursor positioned at the beginning of the first List Item, press // backward delete const listItemField = within( listItemBlock ).getByLabelText( /Text input. .*One.*/ ); selectRangeInRichText( listItemField, 0 ); fireEvent( listItemField, 'onKeyDown', { nativeEvent: {}, preventDefault() {}, keyCode: BACKSPACE, } ); // Inner blocks batch store updates with microtasks. // To avoid `act` warnings, we let queued microtasks to be executed. // Reference: https://t.ly/b95nA await act( async () => {} ); expect( getEditorHtml() ).toMatchInlineSnapshot( ` "<!-- wp:paragraph --> <p>A quick brown fox.</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>One</p> <!-- /wp:paragraph --> <!-- wp:list --> <ul class="wp-block-list"><!-- wp:list-item --> <li>Two</li> <!-- /wp:list-item --> <!-- wp:list-item --> <li>Three</li> <!-- /wp:list-item --></ul> <!-- /wp:list -->" ` ); } ); } );