From b3382f31631433684ad0872228dff25b7b88f94c Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 13 Jan 2022 16:46:58 +0100 Subject: [PATCH 1/5] Mobile - RichText - Use parsed font size values when comparing new changes to avoid not matching values that generate a render loop --- ...gutenberg-editor-typography@canary.test.js | 58 +++++++++++++++++++ .../rich-text/src/component/index.native.js | 29 +++++++--- 2 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 packages/react-native-editor/__device-tests__/gutenberg-editor-typography@canary.test.js diff --git a/packages/react-native-editor/__device-tests__/gutenberg-editor-typography@canary.test.js b/packages/react-native-editor/__device-tests__/gutenberg-editor-typography@canary.test.js new file mode 100644 index 0000000000000..d26b5dee6ac0a --- /dev/null +++ b/packages/react-native-editor/__device-tests__/gutenberg-editor-typography@canary.test.js @@ -0,0 +1,58 @@ +/** + * Internal dependencies + */ +import { isAndroid } from './helpers/utils'; + +const initialHTML = ` +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet ut nibh vitae ornare. Sed auctor nec augue at blandit.

+ + + +

Suspendisse mattis tellus sem, ornare porttitor nisi efficitur vitae.

+ + + +

Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nam blandit rhoncus hendrerit.

+ + + +

Nulla consequat mollis ipsum, nec mattis velit varius non. In convallis aliquet ultrices. Morbi nec nibh et arcu porta tempus.

+ + + +

Cras accumsan lacus nunc, a dapibus tortor porta in.

+`; + +describe( 'Gutenberg Editor Typography test', () => { + it( 'should be able to create a post with custom typography', async () => { + await editorPage.setHtmlContent( initialHTML ); + + const lastBlockAccessibilityLabel = + 'Paragraph Block. Row 5. Cras accumsan lacus nunc, a dapibus tortor porta in.'; + let lastBlockElement; + if ( isAndroid() ) { + lastBlockElement = await editorPage.androidScrollAndReturnElement( + lastBlockAccessibilityLabel + ); + } else { + lastBlockElement = await editorPage.getLastElementByXPath( + lastBlockAccessibilityLabel + ); + if ( ! lastBlockElement ) { + const retryDelay = 5000; + // eslint-disable-next-line no-console + console.log( + `Warning: "lastBlockElement" was not found in the first attempt. Could be that all the blocks were not loaded yet. + Will retry one more time after ${ retryDelay / 1000 } seconds.`, + lastBlockElement + ); + await editorPage.driver.sleep( retryDelay ); + lastBlockElement = await editorPage.getLastElementByXPath( + lastBlockAccessibilityLabel + ); + } + } + + expect( lastBlockElement ).toBeTruthy(); + } ); +} ); diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 8eba7874e1f36..62299a092a59f 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -836,8 +836,10 @@ export class RichText extends Component { this._editor.blur(); } - const currentFontSizeStyle = parseFloat( style?.fontSize ); - const prevFontSizeStyle = parseFloat( prevProps?.style?.fontSize ); + const currentFontSizeStyle = this.getParsedFontSize( style?.fontSize ); + const prevFontSizeStyle = this.getParsedFontSize( + prevProps?.style?.fontSize + ); const isDifferentTag = prevProps.tagName !== tagName; if ( ( currentFontSize && @@ -891,6 +893,20 @@ export class RichText extends Component { }; } + getParsedFontSize( fontSize ) { + const { height, width } = Dimensions.get( 'window' ); + const cssUnitOptions = { height, width, fontSize: DEFAULT_FONT_SIZE }; + + if ( ! fontSize ) { + return fontSize; + } + + const selectedPxValue = + getPxFromCssUnit( fontSize, cssUnitOptions ) ?? DEFAULT_FONT_SIZE; + + return parseFloat( selectedPxValue ); + } + getFontSize( props ) { const { baseGlobalStyles, tagName, fontSize, style } = props; const tagNameFontSize = @@ -913,15 +929,12 @@ export class RichText extends Component { if ( fontSize && ! tagNameFontSize ) { newFontSize = fontSize; } - const { height, width } = Dimensions.get( 'window' ); - const cssUnitOptions = { height, width, fontSize: DEFAULT_FONT_SIZE }; + // We need to always convert to px units because the selected value // could be coming from the web where it could be stored as a different unit. - const selectedPxValue = - getPxFromCssUnit( newFontSize, cssUnitOptions ) ?? - DEFAULT_FONT_SIZE; + const selectedPxValue = this.getParsedFontSize( newFontSize ); - return parseFloat( selectedPxValue ); + return selectedPxValue; } getLineHeight() { From eb6bdb90a5f0dcf5be6a0bca9b1c030c7868f303 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Thu, 13 Jan 2022 18:06:01 +0100 Subject: [PATCH 2/5] Mobile - E2E - Move typography test to full tests instead of canary --- ...ography@canary.test.js => gutenberg-editor-typography.test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/react-native-editor/__device-tests__/{gutenberg-editor-typography@canary.test.js => gutenberg-editor-typography.test.js} (100%) diff --git a/packages/react-native-editor/__device-tests__/gutenberg-editor-typography@canary.test.js b/packages/react-native-editor/__device-tests__/gutenberg-editor-typography.test.js similarity index 100% rename from packages/react-native-editor/__device-tests__/gutenberg-editor-typography@canary.test.js rename to packages/react-native-editor/__device-tests__/gutenberg-editor-typography.test.js From b1cf65b1c3a419e8603c2f650dd2ff7afef1198f Mon Sep 17 00:00:00 2001 From: Gerardo Date: Fri, 14 Jan 2022 13:01:41 +0100 Subject: [PATCH 3/5] Mobile - RichText - Avoid using the fontSize value from the props if there's a font size set from the styles --- packages/rich-text/src/component/index.native.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 62299a092a59f..7d6a2d490e6b5 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -836,6 +836,10 @@ export class RichText extends Component { this._editor.blur(); } + // For font size values changes from the font size picker + // we compare previous values to refresh the selected font size, + // this is also used when the tag name changes + // e.g Heading block and a level change like h1->h2. const currentFontSizeStyle = this.getParsedFontSize( style?.fontSize ); const prevFontSizeStyle = this.getParsedFontSize( prevProps?.style?.fontSize @@ -914,19 +918,26 @@ export class RichText extends Component { let newFontSize = DEFAULT_FONT_SIZE; + // For block-based themes, get the default editor font size. if ( baseGlobalStyles?.typography?.fontSize ) { newFontSize = baseGlobalStyles?.typography?.fontSize; } + // For block-based themes, get the default element font size + // e.g h1, h2. if ( tagNameFontSize ) { newFontSize = tagNameFontSize; } + // For font size values provided from the styles, + // usually from values set from the font size picker. if ( style?.fontSize ) { newFontSize = style.fontSize; } - if ( fontSize && ! tagNameFontSize ) { + // Fall-back to a font size provided from its props (if there's any) + // and there are no other default values to use. + if ( fontSize && ! tagNameFontSize && ! style?.fontSize ) { newFontSize = fontSize; } From 577813fa19377a30724a24e6b291a307edd6f889 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Fri, 14 Jan 2022 13:03:13 +0100 Subject: [PATCH 4/5] Mobile - E2E - Remove test and move some test cases into the current integration tests --- .../gutenberg-editor-typography.test.js | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 packages/react-native-editor/__device-tests__/gutenberg-editor-typography.test.js diff --git a/packages/react-native-editor/__device-tests__/gutenberg-editor-typography.test.js b/packages/react-native-editor/__device-tests__/gutenberg-editor-typography.test.js deleted file mode 100644 index d26b5dee6ac0a..0000000000000 --- a/packages/react-native-editor/__device-tests__/gutenberg-editor-typography.test.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Internal dependencies - */ -import { isAndroid } from './helpers/utils'; - -const initialHTML = ` -

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet ut nibh vitae ornare. Sed auctor nec augue at blandit.

- - - -

Suspendisse mattis tellus sem, ornare porttitor nisi efficitur vitae.

- - - -

Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nam blandit rhoncus hendrerit.

- - - -

Nulla consequat mollis ipsum, nec mattis velit varius non. In convallis aliquet ultrices. Morbi nec nibh et arcu porta tempus.

- - - -

Cras accumsan lacus nunc, a dapibus tortor porta in.

-`; - -describe( 'Gutenberg Editor Typography test', () => { - it( 'should be able to create a post with custom typography', async () => { - await editorPage.setHtmlContent( initialHTML ); - - const lastBlockAccessibilityLabel = - 'Paragraph Block. Row 5. Cras accumsan lacus nunc, a dapibus tortor porta in.'; - let lastBlockElement; - if ( isAndroid() ) { - lastBlockElement = await editorPage.androidScrollAndReturnElement( - lastBlockAccessibilityLabel - ); - } else { - lastBlockElement = await editorPage.getLastElementByXPath( - lastBlockAccessibilityLabel - ); - if ( ! lastBlockElement ) { - const retryDelay = 5000; - // eslint-disable-next-line no-console - console.log( - `Warning: "lastBlockElement" was not found in the first attempt. Could be that all the blocks were not loaded yet. - Will retry one more time after ${ retryDelay / 1000 } seconds.`, - lastBlockElement - ); - await editorPage.driver.sleep( retryDelay ); - lastBlockElement = await editorPage.getLastElementByXPath( - lastBlockAccessibilityLabel - ); - } - } - - expect( lastBlockElement ).toBeTruthy(); - } ); -} ); From 60ca367fba5b2ea3d976151cb17746eec243de4f Mon Sep 17 00:00:00 2001 From: Gerardo Date: Fri, 14 Jan 2022 13:31:59 +0100 Subject: [PATCH 5/5] Mobile - RichTest - Update tests --- .../test/__snapshots__/index.native.js.snap | 65 +++++++++++++++ packages/rich-text/src/test/index.native.js | 83 +++++++++++++++---- 2 files changed, 133 insertions(+), 15 deletions(-) create mode 100644 packages/rich-text/src/test/__snapshots__/index.native.js.snap diff --git a/packages/rich-text/src/test/__snapshots__/index.native.js.snap b/packages/rich-text/src/test/__snapshots__/index.native.js.snap new file mode 100644 index 0000000000000..49c9a7dad92da --- /dev/null +++ b/packages/rich-text/src/test/__snapshots__/index.native.js.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` Font Size renders component with style and font size 1`] = ` +" +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet ut nibh vitae ornare. Sed auctor nec augue at blandit.

+" +`; + +exports[` Font Size should update the font size when style prop with font size property is provided 1`] = ` + + + +`; + +exports[` Font Size should update the font size with decimals when style prop with font size property is provided 1`] = ` + + + +`; diff --git a/packages/rich-text/src/test/index.native.js b/packages/rich-text/src/test/index.native.js index b48d882832649..f91e2e18b4bc0 100644 --- a/packages/rich-text/src/test/index.native.js +++ b/packages/rich-text/src/test/index.native.js @@ -1,16 +1,26 @@ -jest.mock( '@wordpress/data/src/components/use-select' ); /** * External dependencies */ import { Dimensions } from 'react-native'; -import { render } from 'test/helpers'; +import { getEditorHtml, render, initializeEditor } from 'test/helpers'; + /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; +import { select } from '@wordpress/data'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { coreBlocks, registerBlock } from '@wordpress/block-library'; +import { + getBlockTypes, + setDefaultBlockName, + unregisterBlockType, +} from '@wordpress/blocks'; +import '@wordpress/jest-console'; + /** * Internal dependencies */ +import { store as richTextStore } from '../store'; import RichText from '../component/index.native'; /** @@ -25,16 +35,12 @@ const mockGlobalSettings = ( const DEFAULT_GLOBAL_STYLES = { __experimentalGlobalStylesBaseStyles: { typography: { fontSize } }, }; - const selectMock = { - getFormatTypes: jest.fn().mockReturnValue( [] ), - getBlockParents: jest.fn(), - getBlock: jest.fn(), - getSettings: jest.fn().mockReturnValue( DEFAULT_GLOBAL_STYLES ), - }; - - useSelect.mockImplementation( ( callback ) => { - return callback( () => selectMock ); - } ); + jest.spyOn( select( blockEditorStore ), 'getSettings' ).mockReturnValue( + DEFAULT_GLOBAL_STYLES + ); + jest.spyOn( select( richTextStore ), 'getFormatTypes' ).mockReturnValue( + [] + ); }; describe( '', () => { @@ -51,6 +57,13 @@ describe( '', () => { [ '1.42vh', 19 ], ]; + beforeAll( () => { + // Register Paragraph block + const paragraph = coreBlocks[ 'core/paragraph' ]; + registerBlock( paragraph ); + setDefaultBlockName( paragraph.name ); + } ); + beforeEach( () => { mockGlobalSettings( {} ); } ); @@ -59,6 +72,13 @@ describe( '', () => { Dimensions.set( { window } ); } ); + afterAll( () => { + // Clean up registered blocks + getBlockTypes().forEach( ( block ) => { + unregisterBlockType( block.name ); + } ); + } ); + describe( 'Font Size', () => { it( 'should display rich text at the DEFAULT font size.', () => { // Arrange @@ -133,10 +153,10 @@ describe( '', () => { } ); - it( `should display rich text at the font size computed from the LOCAL \`fontSize\` CSS with HIGHEST PRIORITY + it( `should display rich text at the font size computed from the LOCAL \`style.fontSize\` CSS with HIGHEST PRIORITY when CSS is provided ambiguously from ALL possible sources.`, () => { // Arrange - const expectedFontSize = 2; + const expectedFontSize = 1; mockGlobalSettings( { fontSize: '0' } ); // Act const { getByA11yLabel } = render( @@ -193,5 +213,38 @@ describe( '', () => { const actualFontSize = getByA11yLabel( 'editor' ).props.fontSize; expect( actualFontSize ).toBe( expectedFontSize ); } ); + + it( 'should update the font size when style prop with font size property is provided', () => { + // Arrange + const fontSize = '10'; + const style = { fontSize: '12' }; + // Act + const screen = render( ); + screen.update( ); + // Assert + expect( screen.toJSON() ).toMatchSnapshot(); + } ); + + it( 'renders component with style and font size', async () => { + // Arrange + const initialHtml = ` +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet ut nibh vitae ornare. Sed auctor nec augue at blandit.

+ `; + // Act + await initializeEditor( { initialHtml } ); + // Assert + expect( getEditorHtml() ).toMatchSnapshot(); + } ); + + it( 'should update the font size with decimals when style prop with font size property is provided', () => { + // Arrange + const fontSize = '10'; + const style = { fontSize: '12.56px' }; + // Act + const screen = render( ); + screen.update( ); + // Assert + expect( screen.toJSON() ).toMatchSnapshot(); + } ); } ); } );