diff --git a/packages/edit-post/CHANGELOG.md b/packages/edit-post/CHANGELOG.md index 55d3affac68770..52bbfd658b1b2c 100644 --- a/packages/edit-post/CHANGELOG.md +++ b/packages/edit-post/CHANGELOG.md @@ -1,3 +1,9 @@ +## Master + +### Refactor + +- Create EditorInitializer component and implement for various things to initialize as the editor is loaded. This replaces the `__unstableInitialize` refactor done in #14740. ([#15444](https://github.com/WordPress/gutenberg/pull/15444)) + ## 3.4.0 (2019-05-21) ### New Feature @@ -8,7 +14,6 @@ - convert `INIT` effect to controls & actions [#14740](https://github.com/WordPress/gutenberg/pull/14740) - ## 3.2.0 (2019-03-06) ### Polish diff --git a/packages/edit-post/src/components/editor-initialization/index.js b/packages/edit-post/src/components/editor-initialization/index.js new file mode 100644 index 00000000000000..51cb90681f8ae8 --- /dev/null +++ b/packages/edit-post/src/components/editor-initialization/index.js @@ -0,0 +1,37 @@ +/** + * WordPress dependencies + */ +import { useEffect } from '@wordpress/element'; +import { useDispatch } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { + useAdjustSidebarListener, + useBlockSelectionListener, + useUpdatePostLinkListener, +} from './listener-hooks'; + +/** + * Data component used for initializing the editor and re-initializes + * when postId changes or on unmount. + * + * @param {number} postId The id of the post. + * @return {null} This is a data component so does not render any ui. + */ +export default function( { postId } ) { + useAdjustSidebarListener( postId ); + useBlockSelectionListener( postId ); + useUpdatePostLinkListener( postId ); + const { triggerGuide } = useDispatch( 'core/nux' ); + useEffect( () => { + triggerGuide( [ + 'core/editor.inserter', + 'core/editor.settings', + 'core/editor.preview', + 'core/editor.publish', + ] ); + }, [ triggerGuide ] ); + return null; +} diff --git a/packages/edit-post/src/components/editor-initialization/listener-hooks.js b/packages/edit-post/src/components/editor-initialization/listener-hooks.js new file mode 100644 index 00000000000000..56d7761270eac4 --- /dev/null +++ b/packages/edit-post/src/components/editor-initialization/listener-hooks.js @@ -0,0 +1,106 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect, useRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { + STORE_KEY, + VIEW_AS_LINK_SELECTOR, + VIEW_AS_PREVIEW_LINK_SELECTOR, +} from '../../store/constants'; + +/** + * This listener hook monitors for block selection and triggers the appropriate + * sidebar state. + * + * @param {number} postId The current post id. + */ +export const useBlockSelectionListener = ( postId ) => { + const { + hasBlockSelection, + isEditorSidebarOpened, + } = useSelect( + ( select ) => ( { + hasBlockSelection: !! select( + 'core/block-editor' + ).getBlockSelectionStart(), + isEditorSidebarOpened: select( STORE_KEY ).isEditorSidebarOpened(), + } ), + [ postId ] + ); + + const { openGeneralSidebar } = useDispatch( STORE_KEY ); + + useEffect( () => { + if ( ! isEditorSidebarOpened ) { + return; + } + if ( hasBlockSelection ) { + openGeneralSidebar( 'edit-post/block' ); + } else { + openGeneralSidebar( 'edit-post/document' ); + } + }, [ hasBlockSelection, isEditorSidebarOpened ] ); +}; + +/** + * This listener hook is used to monitor viewport size and adjust the sidebar + * accordingly. + * + * @param {number} postId The current post id. + */ +export const useAdjustSidebarListener = ( postId ) => { + const { isSmall, sidebarToReOpenOnExpand } = useSelect( + ( select ) => ( { + isSmall: select( 'core/viewport' ).isViewportMatch( '< medium' ), + sidebarToReOpenOnExpand: select( STORE_KEY ).getActiveGeneralSidebarName(), + } ), + [ postId ] + ); + + const { openGeneralSidebar, closeGeneralSidebar } = useDispatch( STORE_KEY ); + + const previousOpenedSidebar = useRef( '' ); + + useEffect( () => { + if ( isSmall && sidebarToReOpenOnExpand ) { + previousOpenedSidebar.current = sidebarToReOpenOnExpand; + closeGeneralSidebar(); + } else if ( ! isSmall && previousOpenedSidebar.current ) { + openGeneralSidebar( previousOpenedSidebar.current ); + previousOpenedSidebar.current = ''; + } + }, [ isSmall, sidebarToReOpenOnExpand ] ); +}; + +/** + * This listener hook monitors any change in permalink and updates the view + * post link in the admin bar. + * + * @param {number} postId + */ +export const useUpdatePostLinkListener = ( postId ) => { + const { newPermalink } = useSelect( + ( select ) => ( { + newPermalink: select( 'core/editor' ).getCurrentPost().link, + } ), + [ postId ] + ); + const nodeToUpdate = useRef(); + + useEffect( () => { + nodeToUpdate.current = document.querySelector( VIEW_AS_PREVIEW_LINK_SELECTOR ) || + document.querySelector( VIEW_AS_LINK_SELECTOR ); + }, [ postId ] ); + + useEffect( () => { + if ( ! newPermalink || ! nodeToUpdate.current ) { + return; + } + nodeToUpdate.current.setAttribute( 'href', newPermalink ); + }, [ newPermalink ] ); +}; diff --git a/packages/edit-post/src/components/editor-initialization/test/listener-hooks.js b/packages/edit-post/src/components/editor-initialization/test/listener-hooks.js new file mode 100644 index 00000000000000..350a23f5b0ca39 --- /dev/null +++ b/packages/edit-post/src/components/editor-initialization/test/listener-hooks.js @@ -0,0 +1,255 @@ +/** + * External dependencies + */ +import TestRenderer, { act } from 'react-test-renderer'; + +/** + * WordPress dependencies + */ +import { RegistryProvider } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { + useBlockSelectionListener, + useAdjustSidebarListener, + useUpdatePostLinkListener, +} from '../listener-hooks'; +import { STORE_KEY } from '../../../store/constants'; + +describe( 'listener hook tests', () => { + const mockStores = { + 'core/block-editor': { + getBlockSelectionStart: jest.fn(), + }, + 'core/editor': { + getCurrentPost: jest.fn(), + }, + 'core/viewport': { + isViewportMatch: jest.fn(), + }, + [ STORE_KEY ]: { + isEditorSidebarOpened: jest.fn(), + openGeneralSidebar: jest.fn(), + closeGeneralSidebar: jest.fn(), + getActiveGeneralSidebarName: jest.fn(), + }, + }; + let subscribeTrigger; + const registry = { + select: jest.fn().mockImplementation( + ( storeName ) => mockStores[ storeName ] + ), + dispatch: jest.fn().mockImplementation( + ( storeName ) => mockStores[ storeName ] + ), + subscribe: ( subscription ) => { + subscribeTrigger = subscription; + }, + }; + const setMockReturnValue = ( store, functionName, value ) => { + mockStores[ store ][ functionName ] = jest.fn().mockReturnValue( value ); + }; + const getSpyedFunction = ( + store, + functionName + ) => mockStores[ store ][ functionName ]; + const renderComponent = ( testedHook, id, renderer = null ) => { + const TestComponent = ( { postId } ) => { + testedHook( postId ); + return null; + }; + const TestedOutput = + + ; + return renderer === null ? + TestRenderer.create( TestedOutput ) : + renderer.update( TestedOutput ); + }; + afterEach( () => { + Object.values( mockStores ).forEach( ( storeMocks ) => { + Object.values( storeMocks ).forEach( ( mock ) => { + mock.mockClear(); + } ); + } ); + subscribeTrigger = undefined; + } ); + describe( 'useBlockSelectionListener', () => { + it( 'does nothing when editor sidebar is not open', () => { + setMockReturnValue( STORE_KEY, 'isEditorSidebarOpened', false ); + act( () => { + renderComponent( useBlockSelectionListener, 10 ); + } ); + expect( + getSpyedFunction( STORE_KEY, 'isEditorSidebarOpened' ) + ).toHaveBeenCalled(); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).toHaveBeenCalledTimes( 0 ); + } ); + it( 'opens block sidebar if block is selected', () => { + setMockReturnValue( STORE_KEY, 'isEditorSidebarOpened', true ); + setMockReturnValue( 'core/block-editor', 'getBlockSelectionStart', true ); + act( () => { + renderComponent( useBlockSelectionListener, 10 ); + } ); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).toHaveBeenCalledWith( 'edit-post/block' ); + } ); + it( 'opens document sidebar if block is not selected', () => { + setMockReturnValue( STORE_KEY, 'isEditorSidebarOpened', true ); + setMockReturnValue( 'core/block-editor', 'getBlockSelectionStart', false ); + act( () => { + renderComponent( useBlockSelectionListener, 10 ); + } ); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).toHaveBeenCalledWith( 'edit-post/document' ); + } ); + } ); + describe( 'useAdjustSidebarListener', () => { + it( 'initializes and does nothing when viewport is not small', () => { + setMockReturnValue( 'core/viewport', 'isViewPortMatch', false ); + setMockReturnValue( STORE_KEY, 'getActiveGeneralSidebarName', 'edit-post/document' ); + act( () => { + renderComponent( useAdjustSidebarListener, 10 ); + } ); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).not.toHaveBeenCalled(); + expect( + getSpyedFunction( STORE_KEY, 'closeGeneralSidebar' ) + ).not.toHaveBeenCalled(); + } ); + it( 'does not close sidebar if viewport is small and there is no ' + + 'active sidebar name available', () => { + setMockReturnValue( 'core/viewport', 'isViewPortMatch', true ); + setMockReturnValue( STORE_KEY, 'getActiveGeneralSidebarName', null ); + act( () => { + renderComponent( useAdjustSidebarListener, 10 ); + } ); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).not.toHaveBeenCalled(); + expect( + getSpyedFunction( STORE_KEY, 'closeGeneralSidebar' ) + ).not.toHaveBeenCalled(); + } ); + it( 'closes sidebar if viewport is small and there is an active ' + + 'sidebar name available', () => { + setMockReturnValue( 'core/viewport', 'isViewportMatch', true ); + setMockReturnValue( STORE_KEY, 'getActiveGeneralSidebarName', 'foo' ); + act( () => { + renderComponent( useAdjustSidebarListener, 10 ); + } ); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).not.toHaveBeenCalled(); + expect( + getSpyedFunction( STORE_KEY, 'closeGeneralSidebar' ) + ).toHaveBeenCalledTimes( 1 ); + } ); + it( 'opens sidebar if viewport is not small, and there is a cached sidebar to ' + + 'reopen on expand', () => { + setMockReturnValue( 'core/viewport', 'isViewportMatch', true ); + setMockReturnValue( STORE_KEY, 'getActiveGeneralSidebarName', 'foo' ); + act( () => { + renderComponent( useAdjustSidebarListener, 10 ); + } ); + setMockReturnValue( 'core/viewport', 'isViewportMatch', false ); + act( () => { + subscribeTrigger(); + } ); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).toHaveBeenCalledWith( 'foo' ); + expect( + getSpyedFunction( STORE_KEY, 'openGeneralSidebar' ) + ).toHaveBeenCalledTimes( 1 ); + expect( + getSpyedFunction( STORE_KEY, 'closeGeneralSidebar' ) + ).toHaveBeenCalledTimes( 1 ); + } ); + } ); + describe( 'useUpdatePostLinkListener', () => { + const setAttribute = jest.fn(); + const mockSelector = jest.fn(); + beforeEach( () => { + document.querySelector = mockSelector.mockReturnValue( { setAttribute } ); + } ); + afterEach( () => { + setAttribute.mockClear(); + mockSelector.mockClear(); + } ); + it( 'updates nothing if there is no view link available', () => { + mockSelector.mockImplementation( () => null ); + setMockReturnValue( + 'core/editor', + 'getCurrentPost', + { link: 'foo' } + ); + act( () => { + renderComponent( useUpdatePostLinkListener, 10 ); + } ); + expect( setAttribute ).not.toHaveBeenCalled(); + } ); + it( 'updates nothing if there is no permalink', () => { + setMockReturnValue( + 'core/editor', + 'getCurrentPost', + { link: '' } + ); + act( () => { + renderComponent( useUpdatePostLinkListener, 10 ); + } ); + expect( setAttribute ).not.toHaveBeenCalled(); + } ); + it( 'only calls document query selector once across renders', () => { + act( () => { + const renderer = renderComponent( useUpdatePostLinkListener, 10 ); + renderComponent( useUpdatePostLinkListener, 20, renderer ); + } ); + expect( mockSelector ).toHaveBeenCalledTimes( 1 ); + act( () => { + subscribeTrigger(); + } ); + expect( mockSelector ).toHaveBeenCalledTimes( 1 ); + } ); + it( 'only updates the permalink when it changes', () => { + setMockReturnValue( + 'core/editor', + 'getCurrentPost', + { link: 'foo' } + ); + act( () => { + renderComponent( useUpdatePostLinkListener, 10 ); + } ); + act( () => { + subscribeTrigger(); + } ); + expect( setAttribute ).toHaveBeenCalledTimes( 1 ); + } ); + it( 'updates the permalink when it changes', () => { + setMockReturnValue( + 'core/editor', + 'getCurrentPost', + { link: 'foo' } + ); + act( () => { + renderComponent( useUpdatePostLinkListener, 10 ); + } ); + setMockReturnValue( + 'core/editor', + 'getCurrentPost', + { link: 'bar' } + ); + act( () => { + subscribeTrigger(); + } ); + expect( setAttribute ).toHaveBeenCalledTimes( 2 ); + expect( setAttribute ).toHaveBeenCalledWith( 'href', 'bar' ); + } ); + } ); +} ); diff --git a/packages/edit-post/src/store/utils.js b/packages/edit-post/src/components/editor-initialization/utils.js similarity index 100% rename from packages/edit-post/src/store/utils.js rename to packages/edit-post/src/components/editor-initialization/utils.js diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js index 88eb7c4a6113fd..92fad75ebef7e8 100644 --- a/packages/edit-post/src/editor.js +++ b/packages/edit-post/src/editor.js @@ -21,6 +21,7 @@ import { */ import preventEventDiscovery from './prevent-event-discovery'; import Layout from './components/layout'; +import EditorInitialization from './components/editor-initialization'; class Editor extends Component { constructor() { @@ -70,6 +71,7 @@ class Editor extends Component { hasFixedToolbar, focusMode, post, + postId, initialEdits, onError, hiddenBlockTypes, @@ -101,6 +103,7 @@ class Editor extends Component { { ...props } > + diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js index cf8070c8c7b4e4..66d8c753b46ad4 100644 --- a/packages/edit-post/src/index.js +++ b/packages/edit-post/src/index.js @@ -9,7 +9,6 @@ import '@wordpress/viewport'; import '@wordpress/notices'; import { registerCoreBlocks } from '@wordpress/block-library'; import { render, unmountComponentAtNode } from '@wordpress/element'; -import { dispatch } from '@wordpress/data'; /** * Internal dependencies @@ -76,14 +75,6 @@ export function initializeEditor( id, postType, postId, settings, initialEdits ) console.warn( "Your browser is using Quirks Mode. \nThis can cause rendering issues such as blocks overlaying meta boxes in the editor. Quirks Mode can be triggered by PHP errors or HTML code appearing before the opening . Try checking the raw page source or your site's PHP error log and resolving errors there, removing any HTML before the doctype, or disabling plugins." ); } - dispatch( 'core/edit-post' ).__unstableInitialize(); - dispatch( 'core/nux' ).triggerGuide( [ - 'core/editor.inserter', - 'core/editor.settings', - 'core/editor.preview', - 'core/editor.publish', - ] ); - render( onChangeListener( - () => !! registry.select( 'core/block-editor' ) - .getBlockSelectionStart(), - ( hasBlockSelection ) => { - if ( ! registry.select( 'core/edit-post' ).isEditorSidebarOpened() ) { - return; - } - if ( hasBlockSelection ) { - registry.dispatch( STORE_KEY ) - .openGeneralSidebar( 'edit-post/block' ); - } else { - registry.dispatch( STORE_KEY ) - .openGeneralSidebar( 'edit-post/document' ); - } - } - ) ); - // hide/show the sidebar depending on size of viewport. - yield __unstableSubscribe( ( registry ) => onChangeListener( - () => registry.select( 'core/viewport' ) - .isViewportMatch( '< medium' ), - ( () => { - let sidebarToReOpenOnExpand = null; - return ( isSmall ) => { - const { getActiveGeneralSidebarName } = registry.select( STORE_KEY ); - const { - closeGeneralSidebar: closeSidebar, - openGeneralSidebar: openSidebar, - } = registry.dispatch( STORE_KEY ); - if ( isSmall ) { - sidebarToReOpenOnExpand = getActiveGeneralSidebarName(); - if ( sidebarToReOpenOnExpand ) { - closeSidebar(); - } - } else if ( - sidebarToReOpenOnExpand && - ! getActiveGeneralSidebarName() - ) { - openSidebar( sidebarToReOpenOnExpand ); - } - }; - } )(), - true - ) ); - // Update View Post link in the admin bar when permalink is updated. - yield __unstableSubscribe( ( registry ) => onChangeListener( - () => registry.select( 'core/editor' ).getCurrentPost().link, - ( newPermalink ) => { - if ( ! newPermalink ) { - return; - } - const nodeToUpdate = document.querySelector( VIEW_AS_LINK_SELECTOR ); - if ( ! nodeToUpdate ) { - return; - } - nodeToUpdate.setAttribute( 'href', newPermalink ); - } - ) ); -} - diff --git a/packages/edit-post/src/store/constants.js b/packages/edit-post/src/store/constants.js index 60f80d914a5c7b..35acac0c5633a8 100644 --- a/packages/edit-post/src/store/constants.js +++ b/packages/edit-post/src/store/constants.js @@ -9,3 +9,9 @@ export const STORE_KEY = 'core/edit-post'; * @type {string} */ export const VIEW_AS_LINK_SELECTOR = '#wp-admin-bar-view a'; + +/** + * CSS selector string for the admin bar preview post link anchor tag. + * @type {string} + */ +export const VIEW_AS_PREVIEW_LINK_SELECTOR = '#wp-admin-bar-preview a'; diff --git a/packages/edit-post/src/store/controls.js b/packages/edit-post/src/store/controls.js index 462741a1734075..3a64e045f69666 100644 --- a/packages/edit-post/src/store/controls.js +++ b/packages/edit-post/src/store/controls.js @@ -21,28 +21,12 @@ export function select( storeName, selectorName, ...args ) { }; } -/** - * Calls a subscriber using the current state. - * - * @param {function} listenerCallback A callback for the subscriber that - * receives the registry. - * @return {Object} control descriptor. - */ -export function __unstableSubscribe( listenerCallback ) { - return { type: 'SUBSCRIBE', listenerCallback }; -} - const controls = { SELECT: createRegistryControl( ( registry ) => ( { storeName, selectorName, args } ) => { return registry.select( storeName )[ selectorName ]( ...args ); } ), - SUBSCRIBE: createRegistryControl( - ( registry ) => ( { listenerCallback } ) => { - return registry.subscribe( listenerCallback( registry ) ); - } - ), }; export default controls; diff --git a/packages/edit-post/src/store/test/actions.js b/packages/edit-post/src/store/test/actions.js index a16e58f9cc18d8..07dc4b81ece682 100644 --- a/packages/edit-post/src/store/test/actions.js +++ b/packages/edit-post/src/store/test/actions.js @@ -15,9 +15,7 @@ import { toggleFeature, togglePinnedPluginItem, requestMetaBoxUpdates, - __unstableInitialize, } from '../actions'; -import { STORE_KEY, VIEW_AS_LINK_SELECTOR } from '../constants'; describe( 'actions', () => { describe( 'openGeneralSidebar', () => { @@ -135,180 +133,4 @@ describe( 'actions', () => { } ); } ); } ); - - describe( '__unstableInitialize', () => { - let fulfillment; - const reset = () => fulfillment = __unstableInitialize(); - const registryMock = { select: {}, dispatch: {} }; - describe( 'yields subscribe control descriptor for block settings', () => { - reset(); - const { value } = fulfillment.next(); - const listenerCallback = value.listenerCallback; - const isEditorSidebarOpened = jest.fn(); - const getBlockSelectionStart = jest.fn(); - const openSidebar = jest.fn(); - beforeEach( () => { - registryMock.select = ( store ) => { - const stores = { - 'core/block-editor': { getBlockSelectionStart }, - 'core/edit-post': { isEditorSidebarOpened }, - }; - return stores[ store ]; - }; - registryMock.dispatch = () => ( { openGeneralSidebar: openSidebar } ); - } ); - afterEach( () => { - isEditorSidebarOpened.mockClear(); - getBlockSelectionStart.mockClear(); - openSidebar.mockClear(); - } ); - it( 'returns subscribe control descriptor', () => { - expect( value.type ).toBe( 'SUBSCRIBE' ); - } ); - it( 'does nothing if sidebar is not opened', () => { - getBlockSelectionStart.mockReturnValue( true ); - isEditorSidebarOpened.mockReturnValue( false ); - const listener = listenerCallback( registryMock ); - getBlockSelectionStart.mockReturnValue( false ); - listener(); - expect( getBlockSelectionStart ).toHaveBeenCalled(); - expect( isEditorSidebarOpened ).toHaveBeenCalled(); - expect( openSidebar ).not.toHaveBeenCalled(); - } ); - it( 'opens block sidebar if block is selected', () => { - isEditorSidebarOpened.mockReturnValue( true ); - getBlockSelectionStart.mockReturnValue( false ); - const listener = listenerCallback( registryMock ); - getBlockSelectionStart.mockReturnValue( true ); - listener(); - expect( openSidebar ).toHaveBeenCalledWith( 'edit-post/block' ); - } ); - it( 'opens document sidebar if block is not selected', () => { - isEditorSidebarOpened.mockReturnValue( true ); - getBlockSelectionStart.mockReturnValue( true ); - const listener = listenerCallback( registryMock ); - getBlockSelectionStart.mockReturnValue( false ); - listener(); - expect( openSidebar ).toHaveBeenCalledWith( 'edit-post/document' ); - } ); - } ); - describe( 'yields subscribe control descriptor for adjusting the ' + - 'sidebar', () => { - reset(); - fulfillment.next(); - const { value } = fulfillment.next(); - const listenerCallback = value.listenerCallback; - const isViewportMatch = jest.fn(); - const getActiveGeneralSidebarName = jest.fn(); - const willCloseGeneralSidebar = jest.fn(); - const willOpenGeneralSidebar = jest.fn(); - beforeEach( () => { - registryMock.select = ( store ) => { - const stores = { - 'core/viewport': { isViewportMatch }, - [ STORE_KEY ]: { getActiveGeneralSidebarName }, - }; - return stores[ store ]; - }; - registryMock.dispatch = ( store ) => { - const stores = { - [ STORE_KEY ]: { - closeGeneralSidebar: willCloseGeneralSidebar, - openGeneralSidebar: willOpenGeneralSidebar, - }, - }; - return stores[ store ]; - }; - registryMock.subscribe = jest.fn(); - isViewportMatch.mockReturnValue( true ); - } ); - afterEach( () => { - isViewportMatch.mockClear(); - getActiveGeneralSidebarName.mockClear(); - willCloseGeneralSidebar.mockClear(); - willOpenGeneralSidebar.mockClear(); - } ); - it( 'returns subscribe control descriptor', () => { - expect( value.type ).toBe( 'SUBSCRIBE' ); - } ); - it( 'initializes and does nothing when viewport is not small', () => { - isViewportMatch.mockReturnValue( false ); - listenerCallback( registryMock )(); - expect( isViewportMatch ).toHaveBeenCalled(); - expect( getActiveGeneralSidebarName ).not.toHaveBeenCalled(); - } ); - it( 'does not close sidebar if viewport is small and there is no ' + - 'active sidebar name available', () => { - getActiveGeneralSidebarName.mockReturnValue( false ); - listenerCallback( registryMock )(); - expect( willCloseGeneralSidebar ).not.toHaveBeenCalled(); - expect( willOpenGeneralSidebar ).not.toHaveBeenCalled(); - } ); - it( 'closes sidebar if viewport is small and there is an active ' + - 'sidebar name available', () => { - getActiveGeneralSidebarName.mockReturnValue( 'someSidebar' ); - listenerCallback( registryMock )(); - expect( willCloseGeneralSidebar ).toHaveBeenCalled(); - expect( willOpenGeneralSidebar ).not.toHaveBeenCalled(); - } ); - it( 'opens sidebar if viewport is not small, there is a cached sidebar to ' + - 'reopen on expand, and there is no current sidebar name available', () => { - getActiveGeneralSidebarName.mockReturnValue( 'someSidebar' ); - const listener = listenerCallback( registryMock ); - listener(); - isViewportMatch.mockReturnValue( false ); - getActiveGeneralSidebarName.mockReturnValue( false ); - listener(); - expect( willCloseGeneralSidebar ).toHaveBeenCalledTimes( 1 ); - expect( willOpenGeneralSidebar ).toHaveBeenCalledTimes( 1 ); - } ); - } ); - describe( 'yields subscribe control descriptor for updating the ' + - 'view post link when the permalink changes', () => { - reset(); - fulfillment.next(); - fulfillment.next(); - const { value } = fulfillment.next(); - const listenerCallback = value.listenerCallback; - const getCurrentPost = jest.fn(); - const setAttribute = jest.fn(); - beforeEach( () => { - document.querySelector = jest.fn().mockReturnValue( { setAttribute } ); - getCurrentPost.mockReturnValue( { link: 'foo' } ); - registryMock.select = ( store ) => { - const stores = { 'core/editor': { getCurrentPost } }; - return stores[ store ]; - }; - } ); - afterEach( () => { - setAttribute.mockClear(); - getCurrentPost.mockClear(); - } ); - it( 'returns expected control descriptor', () => { - expect( value.type ).toBe( 'SUBSCRIBE' ); - } ); - it( 'updates nothing if there is no new permalink', () => { - const listener = listenerCallback( registryMock ); - listener(); - expect( getCurrentPost ).toHaveBeenCalledTimes( 2 ); - expect( document.querySelector ).not.toHaveBeenCalled(); - expect( setAttribute ).not.toHaveBeenCalled(); - } ); - it( 'does not do anything if the node is not found', () => { - const listener = listenerCallback( registryMock ); - getCurrentPost.mockReturnValue( { link: 'bar' } ); - document.querySelector.mockReturnValue( false ); - listener(); - expect( document.querySelector ) - .toHaveBeenCalledWith( VIEW_AS_LINK_SELECTOR ); - expect( setAttribute ).not.toHaveBeenCalled(); - } ); - it( 'updates with the new permalink when node is found', () => { - const listener = listenerCallback( registryMock ); - getCurrentPost.mockReturnValue( { link: 'bar' } ); - listener(); - expect( setAttribute ).toHaveBeenCalledWith( 'href', 'bar' ); - } ); - } ); - } ); } );