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

e2e testing using testID and customStyles #197

Closed
mikbry opened this issue Dec 9, 2020 · 15 comments · Fixed by #198
Closed

e2e testing using testID and customStyles #197

mikbry opened this issue Dec 9, 2020 · 15 comments · Fixed by #198

Comments

@mikbry
Copy link
Contributor

mikbry commented Dec 9, 2020

This component is not designed for e2e testing, see #155.
But i found a workaround using customStyles. In fact customStyles are more customProps for sub-components.
For MenuTrigger:

<MenuTrigger customStyles={{ triggerTouchable: { testID: 'menu-trigger' } }} />

For MenuOption:

<MenuOption customStyles={{ optionTouchable: { testID: 'option-1' } }} />

Tested using Detox on Android emulator

@sjmdocto
Copy link

sjmdocto commented Dec 9, 2020

This works for MenuTrigger, but no testID is showing up for MenuOption for me. I'm using Jest and React Native.

@mikbry
Copy link
Contributor Author

mikbry commented Dec 10, 2020

For me it is working ok testing 4/5 different MenuOptions. And I checked back at MenuOptions source code:

<Touchable
          onPress={() => this._onSelect()}
          {...defaultTouchableProps}
          {...customStyles.optionTouchable}
        >
          {rendered}
</Touchable>

So optionTouchable is the right parameter. Are you testing on iOS or React Web, if so Touchable is a different component TouchableHighlight, I didn't test. Also if MenuOption is disable, the parameter can't be changed to optionWrapper as it is using style instead if props.

@sodik82
Copy link
Contributor

sodik82 commented Dec 10, 2020

This component is not designed for e2e testing, see #155.

PRs are welcomed :) supporting testID makes sense to me

@mikbry
Copy link
Contributor Author

mikbry commented Dec 10, 2020

I work on the e2e PR ;-)
Regarding customStyles not implemented in Touchable as style={customStyles.xxxTouchable} but directly as props is it a bug or ?

@sodik82
Copy link
Contributor

sodik82 commented Dec 11, 2020

thanks @mikbry for PR.

Regarding the question (if I get it right), spreading optionTouchable directly (without style=) was intention so that you can change non-style properties like e.g. underlayColor (see api ). You can always use `optionTouchable={style: {....}} to set the styles.

@mikbry
Copy link
Contributor Author

mikbry commented Dec 11, 2020

Yep but I think it should be named customProps instead of customStyle ?

@sodik82
Copy link
Contributor

sodik82 commented Dec 11, 2020 via email

@sodik82
Copy link
Contributor

sodik82 commented Dec 11, 2020

but yes, it is suboptimal name.

@sjmdocto
Copy link

sjmdocto commented Dec 11, 2020

For me it is working ok testing 4/5 different MenuOptions. And I checked back at MenuOptions source code:

<Touchable
          onPress={() => this._onSelect()}
          {...defaultTouchableProps}
          {...customStyles.optionTouchable}
        >
          {rendered}
</Touchable>

So optionTouchable is the right parameter. Are you testing on iOS or React Web, if so Touchable is a different component TouchableHighlight, I didn't test. Also if MenuOption is disable, the parameter can't be changed to optionWrapper as it is using style instead if props.

The popup menu works fine on iOS/Android simulators, but I'm trying to use Jest to run tests. I'm trying to use React Native Testing Library such that I can find a MenuOption by it's testID, click on that option, and then test my own code. But fireEvent.press() isn't finding the MenuOption's testID. And when I use Jest's snapshot feature, I can find the testID of MenuTrigger, but I can't find any MenuOption's testID's.

I copied the code that you wrote:
<MenuOption customStyles={{ optionTouchable: { testID: 'option-1' } }} />

@mikbry
Copy link
Contributor Author

mikbry commented Dec 12, 2020

@sjmdocto you should test latest version 0.15.10. I added support for testID in MenuOption and MenuTrigger

@CallumHemsley
Copy link

For me it is working ok testing 4/5 different MenuOptions. And I checked back at MenuOptions source code:

<Touchable
          onPress={() => this._onSelect()}
          {...defaultTouchableProps}
          {...customStyles.optionTouchable}
        >
          {rendered}
</Touchable>

So optionTouchable is the right parameter. Are you testing on iOS or React Web, if so Touchable is a different component TouchableHighlight, I didn't test. Also if MenuOption is disable, the parameter can't be changed to optionWrapper as it is using style instead if props.

The popup menu works fine on iOS/Android simulators, but I'm trying to use Jest to run tests. I'm trying to use React Native Testing Library such that I can find a MenuOption by it's testID, click on that option, and then test my own code. But fireEvent.press() isn't finding the MenuOption's testID. And when I use Jest's snapshot feature, I can find the testID of MenuTrigger, but I can't find any MenuOption's testID's.

I copied the code that you wrote: <MenuOption customStyles={{ optionTouchable: { testID: 'option-1' } }} />

Hey @sjmdocto did you find a solution for this? Exact same use case.

Should also be noted I'm on version 0.15.12 @mikbry - looks like fireEvent.press is causing the menu options to show in the DOM.

@charlestbell
Copy link

charlestbell commented Apr 27, 2022

Has anyone gotten Jest fireEvent.press() working?

@plambir93kek
Copy link

No MenuOption in snapshots, also no elements found by testID of menu option.

const menuOptionStyle = useMemo(
    (): MenuOptionCustomStyle => ({
      optionWrapper: {
        ...style.option,
        ...optionStyle
      },
      OptionTouchableComponent: TouchableOpacity,
      optionTouchable: { testID: 'dropdown-option' }
    }),
    [optionStyle]
  );

  return (
    <MenuOption
      customStyles={menuOptionStyle}
      disabled={isDisabled}
      value={value}
      onSelect={handleSelect}>
      {icon && <View style={[style.icon, iconStyle]}>{icon}</View>}
      <AppText style={titleStyle}>{title}</AppText>
    </MenuOption>
  );

@shail-spreadd
Copy link

still not working for me using RNTL fireevent.press is not opening my menu @sodik82

@personalizedrefrigerator
Copy link

personalizedrefrigerator commented Jul 18, 2024

still not working for me using RNTL fireevent.press is not opening my menu

I've had success with mocking both View.measure and View.onLayout (I'm using react-native-testing-library).

For example,

import type * as ReactNative from 'react-native';

// Mock react-native to modify View's constructor.
jest.mock('react-native', () => {
	// See https://jestjs.io/docs/jest-object#jestrequireactualmodulename
	const reactNative = jest.requireActual<typeof ReactNative>('react-native');
	const ViewMock = class extends reactNative.View {
		public constructor(props: ReactNative.ViewProps) {
			super(props);

			// react-native-popup-menu won't show menus until an onLayout event is fired on
			// a View just within its MenuProvider.
			// To work around this, call onLayout for all View components.
			if (this.props.onLayout) {
				this.props.onLayout({ nativeEvent: { layout: { x: 0, y: 0, width: 100, height: 100 } }} as any);
			}
		}

		// The layout for a MenuTrigger is found using .measure. Mock .measure to allow
		// triggers to display menus:
		public measure = (callback: ReactNative.MeasureOnSuccessCallback) => {
			callback(0, 0, 150, 150, 0, 0);
		};
	};

	// Use a Proxy object, rather than {...reactNative, View: ViewMock}. React Native warns
	// when attempting to access certain deprecated properties (which is done by ...reactNative).
	return new Proxy(reactNative, {
		get(target, property) {
			if (property === 'View') {
				return ViewMock;
			}
			return target[property as keyof typeof ReactNative];
		},
	});
});

Then in a test,

...
	test('example test', async () => {
		render(<MyComponent/>);
		// Note: Add testID='menu-trigger-button' to the MenuTrigger:
		const trigger = await screen.findByTestId('menu-trigger-button');
		const user = userEvent.setup();
		user.press(trigger);
		
		// The menu should now be open.
	});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants