diff --git a/packages/plugins/src/components/test/plugin-area.js b/packages/plugins/src/components/test/plugin-area.js new file mode 100644 index 0000000000000..68ed2b5368d03 --- /dev/null +++ b/packages/plugins/src/components/test/plugin-area.js @@ -0,0 +1,121 @@ +/** + * External dependencies + */ +import { act, render, cleanup } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import { getPlugins, unregisterPlugin, registerPlugin } from '../../api'; +import PluginArea from '../plugin-area'; + +describe( 'PluginArea', () => { + afterEach( () => { + // Unmount components before unregistering the plugins. + // RTL uses top-level `afterEach` for cleanup, executed after this teardown. + cleanup(); + getPlugins().forEach( ( plugin ) => { + unregisterPlugin( plugin.name ); + } ); + getPlugins( 'my-app' ).forEach( ( plugin ) => { + unregisterPlugin( plugin.name ); + } ); + } ); + + const TestComponent = ( { content } ) => { + return `plugin: ${ content }.`; + }; + + test( 'renders unscoped plugin', () => { + registerPlugin( 'unscoped', { + render: () => , + icon: 'smiley', + } ); + + const { container } = render( ); + + expect( container ).toHaveTextContent( 'plugin: unscoped.' ); + } ); + + test( 'renders scoped plugin', () => { + registerPlugin( 'scoped', { + render: () => , + icon: 'smiley', + scope: 'my-app', + } ); + + const { container } = render( ); + + expect( container ).toHaveTextContent( 'plugin: scoped.' ); + } ); + + test( 'rerenders when a new plugin is registered', () => { + registerPlugin( 'foo', { + render: () => , + icon: 'smiley', + scope: 'my-app', + } ); + + const { container } = render( ); + + act( () => { + registerPlugin( 'bar', { + render: () => , + icon: 'smiley', + scope: 'my-app', + } ); + } ); + + expect( container ).toHaveTextContent( 'plugin: bar.' ); + } ); + + test( 'rerenders when a plugin is unregistered', () => { + registerPlugin( 'one', { + render: () => , + icon: 'smiley', + scope: 'my-app', + } ); + registerPlugin( 'two', { + render: () => , + icon: 'smiley', + scope: 'my-app', + } ); + + const { container } = render( ); + + expect( container ).toHaveTextContent( 'plugin: one.plugin: two.' ); + + act( () => { + unregisterPlugin( 'one' ); + } ); + + expect( container ).toHaveTextContent( 'plugin: two.' ); + } ); + + test.failing( + 'does not rerender when a plugin is added to a different scope', + () => { + const ComponentSpy = jest.fn( ( { content } ) => { + return `plugin: ${ content }.`; + } ); + + registerPlugin( 'scoped', { + render: () => , + icon: 'smiley', + scope: 'my-app', + } ); + + render( ); + + act( () => { + registerPlugin( 'unscoped', { + render: () => , + icon: 'smiley', + } ); + } ); + + // Any store update triggers setState and causes PluginArea to rerender. + expect( ComponentSpy ).toHaveBeenCalledTimes( 1 ); + } + ); +} );