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

[RNMobile] Add integration test helpers #38619

Merged
merged 9 commits into from
Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ A test can be structured with the following parts:

We also include examples of common tasks as well as tips in the following sections:

- [Helpers](#helpers)
- [Common flows](#common-flows)
- [Tools](#tools)
- [Common pitfalls and caveats](#common-pitfalls-and-caveats)
Expand Down Expand Up @@ -211,6 +212,10 @@ afterAll( () => {
} );
```

## Helpers

In the spirit of making easier writing integration tests for the native version, you can find a list of helper functions in [this README](https://github.com/WordPress/gutenberg/blob/HEAD/test/native/integration-test-helpers/README.md).

## Common flows

### Query a block
Expand Down
209 changes: 11 additions & 198 deletions packages/block-library/src/gallery/test/helpers.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,83 +2,25 @@
* External dependencies
*/
import {
act,
initializeEditor,
addBlock,
fireEvent,
waitFor,
within,
waitForStoreResolvers,
getBlock,
getInnerBlock,
initializeEditor,
triggerBlockListLayout,
} from 'test/helpers';

/**
* WordPress dependencies
*/
import {
requestMediaPicker,
subscribeMediaUpload,
} from '@wordpress/react-native-bridge';
import {
MEDIA_UPLOAD_STATE_UPLOADING,
MEDIA_UPLOAD_STATE_SUCCEEDED,
MEDIA_UPLOAD_STATE_FAILED,
MEDIA_UPLOAD_STATE_RESET,
} from '@wordpress/block-editor';

/**
* Adds a Gallery block via the block picker.
*
* @return {import('@testing-library/react-native').RenderAPI} A Testing Library screen.
*/
export const addGalleryBlock = async () => {
const screen = await initializeEditor();
const { getByA11yLabel, getByTestId, getByText } = screen;

fireEvent.press( getByA11yLabel( 'Add block' ) );

const blockList = getByTestId( 'InserterUI-Blocks' );
// onScroll event used to force the FlatList to render all items
fireEvent.scroll( blockList, {
nativeEvent: {
contentOffset: { y: 0, x: 0 },
contentSize: { width: 100, height: 100 },
layoutMeasurement: { width: 100, height: 100 },
},
} );

fireEvent.press( await waitFor( () => getByText( 'Gallery' ) ) );

await addBlock( screen, 'Gallery' );
return screen;
};

/**
* The gallery items are rendered via the FlatList of the inner block list.
* In order to render the items of a FlatList, it's required to trigger the
* "onLayout" event. Additionally, the call is wrapped over "waitForStoreResolvers"
* because the gallery items request the media data associated with the image to
* be rendered via the "getMedia" selector.
*
* @param {import('react-test-renderer').ReactTestInstance} galleryBlock Gallery block instance to trigger layout event.
* @param {Object} [options] Configuration options for the event.
* @param {number} [options.width] Width value to be passed to the event.
*/
export const triggerGalleryLayout = async (
galleryBlock,
{ width = 320 } = {}
) =>
waitForStoreResolvers( () =>
fireEvent(
within( galleryBlock ).getByTestId( 'block-list-wrapper' ),
'layout',
{
nativeEvent: {
layout: {
width,
},
},
}
)
);

/**
* Initialize the editor with HTML generated of Gallery block.
*
Expand Down Expand Up @@ -106,12 +48,11 @@ export const initializeWithGalleryBlock = async ( {
useLocalUrl,
} );
const screen = await initializeEditor( { initialHtml } );
const { getByA11yLabel } = screen;

const galleryBlock = getByA11yLabel( /Gallery Block\. Row 1/ );
const galleryBlock = getBlock( screen, 'Gallery' );

if ( numberOfItems > 0 ) {
await triggerGalleryLayout( galleryBlock, { width } );
await triggerBlockListLayout( galleryBlock, { width } );
}

if ( selected ) {
Expand All @@ -125,109 +66,11 @@ export const initializeWithGalleryBlock = async ( {
* Gets a gallery item within a Gallery block.
*
* @param {import('react-test-renderer').ReactTestInstance} galleryBlock Gallery block instance.
* @param {number} rowPosition Row position within the Gallery block.
* @param {number} rowIndex Row position within the Gallery block.
* @return {import('react-test-renderer').ReactTestInstance} Gallery item.
*/
export const getGalleryItem = ( galleryBlock, rowPosition ) => {
return within( galleryBlock ).getByA11yLabel(
new RegExp( `Image Block\\. Row ${ rowPosition }` )
);
};

/**
* Sets up the media upload mock functions for testing.
*
* @typedef {Object} MediaUploadMockFunctions
* @property {Function} notifyUploadingState Notify uploading state for a media item.
* @property {Function} notifySucceedState Notify succeed state for a media item.
* @property {Function} notifyFailedState Notify failed state for a media item.
* @property {Function} notifyResetState Notify reset state for a media item.
*
* @return {MediaUploadMockFunctions} Notify state functions.
*/
export const setupMediaUpload = () => {
const mediaUploadListeners = [];
subscribeMediaUpload.mockImplementation( ( callback ) => {
mediaUploadListeners.push( callback );
return { remove: jest.fn() };
} );
const notifyMediaUpload = ( payload ) =>
mediaUploadListeners.forEach( ( listener ) => listener( payload ) );

return {
notifyUploadingState: async ( mediaItem ) =>
act( async () => {
notifyMediaUpload( {
state: MEDIA_UPLOAD_STATE_UPLOADING,
mediaId: mediaItem.localId,
progress: 0.25,
} );
} ),
notifySucceedState: async ( mediaItem ) =>
act( async () => {
notifyMediaUpload( {
state: MEDIA_UPLOAD_STATE_SUCCEEDED,
mediaId: mediaItem.localId,
mediaUrl: mediaItem.serverUrl,
mediaServerId: mediaItem.serverId,
} );
} ),
notifyFailedState: async ( mediaItem ) =>
act( async () => {
notifyMediaUpload( {
state: MEDIA_UPLOAD_STATE_FAILED,
mediaId: mediaItem.localId,
progress: 0.5,
} );
} ),
notifyResetState: async ( mediaItem ) =>
act( async () => {
notifyMediaUpload( {
state: MEDIA_UPLOAD_STATE_RESET,
mediaId: mediaItem.localId,
progress: 0,
} );
} ),
};
};

/**
*
* Sets up Media Picker mock functions.
*
* @typedef {Object} MediaPickerMockFunctions
* @property {Function} expectMediaPickerCall Checks if the request media picker function has been called with specific arguments.
* @property {Function} mediaPickerCallback Callback function to notify the media items picked from the media picker.
*
* @return {MediaPickerMockFunctions} Media picker mock functions.
*/
export const setupMediaPicker = () => {
let mediaPickerCallback;
requestMediaPicker.mockImplementation(
( source, filter, multiple, callback ) => {
mediaPickerCallback = callback;
}
);
return {
expectMediaPickerCall: ( source, filter, multiple ) =>
expect( requestMediaPicker ).toHaveBeenCalledWith(
source,
filter,
multiple,
mediaPickerCallback
),
mediaPickerCallback: async ( ...mediaItems ) =>
act( async () =>
mediaPickerCallback(
mediaItems.map( ( { localId, localUrl } ) => ( {
type: 'image',
url: localUrl,
id: localId,
} ) )
)
),
};
};
export const getGalleryItem = ( galleryBlock, rowIndex ) =>
getInnerBlock( galleryBlock, 'Image', { rowIndex } );

/**
* Generates the HTML of a Gallery block.
Expand Down Expand Up @@ -261,33 +104,3 @@ export const generateGalleryBlock = (
<figure class="wp-block-gallery has-nested-images columns-default is-cropped">${ galleryItems }</figure>
<!-- /wp:gallery -->`;
};

/**
* Sets the text of a caption.
*
* @param {import('react-test-renderer').ReactTestInstance} element Caption test instance.
* @param {string} text Text to be set.
*/
export const setCaption = ( element, text ) => {
fireEvent( element, 'focus' );
fireEvent( element, 'onChange', {
nativeEvent: {
eventCount: 1,
target: undefined,
text,
},
} );
};

/**
* Opens the block settings of the current selected block.
*
* @param {import('@testing-library/react-native').RenderAPI} screen The Testing Library screen.
*/
export const openBlockSettings = async ( screen ) => {
const { getByA11yLabel, getByTestId } = screen;
fireEvent.press( getByA11yLabel( 'Open Settings' ) );
await waitFor(
() => getByTestId( 'block-settings-modal' ).props.isVisible
);
};
Loading