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

RNTester: Setup E2E tests for iOS and Android with Appium and Jest #35016

Closed
wants to merge 1 commit into from

Conversation

mateuszm22
Copy link
Contributor

@mateuszm22 mateuszm22 commented Oct 18, 2022

Summary

The motivation is to create an e2e testing solution for the rn-tester default app. With cooperation with Callstack developers, we are trying to make a working tool. Now it's based on wdio+appium.
Next steps:

  • integrate with devices' cloud
  • build an app automatically

Changelog

[General] [Added] - Added first working configuration for e2e testing

Used tools

  • appium (xuitest and uiautomator2)
  • webdriverio

Test Plan

Follow Readme File

Videos

  • Android:
android_Screen.Recording.2022-11-10.at.12.43.52.mov
  • iOS:
iOS_Screen.Recording.2022-11-10.at.11.03.23.mov

@analysis-bot
Copy link

analysis-bot commented Oct 18, 2022

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,457,844 -931
android hermes armeabi-v7a 7,781,014 -977
android hermes x86 8,933,699 -956
android hermes x86_64 8,790,794 -960
android jsc arm64-v8a 9,092,326 -642
android jsc armeabi-v7a 8,290,348 -675
android jsc x86 9,143,079 -680
android jsc x86_64 9,401,977 -666

Base commit: 270584a
Branch: main

@analysis-bot
Copy link

analysis-bot commented Oct 18, 2022

Platform Engine Arch Size (bytes) Diff
ios - universal n/a --

Base commit: efd39ee
Branch: main

@react-native-bot react-native-bot added the No CLA Authors need to sign the CLA before a PR can be reviewed. label Oct 19, 2022
@facebook-github-bot
Copy link
Contributor

Hi @mateuszm22!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at [email protected]. Thanks!

@react-native-bot react-native-bot added the Type: Enhancement A new feature or enhancement of an existing feature. label Oct 24, 2022
@pull-bot
Copy link

PR build artifact for 0a186ee is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for 0a186ee is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@@ -0,0 +1,41 @@
import { defineFeature, loadFeature } from 'jest-cucumber';
import { givenUserOnMainPage } from '../common_steps/commonSteps.steps';
import { thenVerifyAlertBoxHasText, thenVerifyThatTheButtonComponentIsDisplayed, thenVerifyThatTheButtonHeaderIsDisplayed, whenUserClicksOnTheButtonComponent, whenUserClicksOnTheCancelApplicationButton, whenUserClicksOnTheOKButton, whenUserClicksOnTheSubmitApplicationButton } from '../steps/buttonComponentScreen.steps';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like unnecessary decoupling of code that's tightly coupled with this file. I believe we could move all of those helpers into this file and achieve similar readability and higher code colocation

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been resolved by importing all functions (*). Then one line to be able to use the functions without an alias. Please, check if the current implementation is suitable

};

export const whenUserClicksOnTheSubmitApplicationButton = (when) => {
when(/^User clicks on the Submit Application button$/, async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could have been a regular string instead of a regex, right?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should keep the consistency of the steps format

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a regex rather an exception from the rule of using strings. There's nothing wrong with having a little bit of inconsistency here. Personally it would be just harder for me to write a working regex than a plain string. Using a regex also triggers a different mental path for me (my mind goes "whats weird about this code that it uses regex instead of a string?" – if it finds nothing weird, then it's the time that I could save by using a faster string lookup that I'd normally expect). Again, I'm speaking for my own. If you find this is saving you time and no one else complains, please go with it

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have checked couple of repos to verify how it is resolved there. Most of them use consistent regex format for every step. But we are fine with both approaches. I understand your point of view. I have changed steps to the expected format. Thanks! c:

Comment on lines 10 to 15
if (process.env.E2E_DEVICE.includes('ios')) {
deviceLocator = this.buttonComponentIOS;
}
if (process.env.E2E_DEVICE .includes('android')) {
deviceLocator = this.buttonComponent;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if more of similar logic is expected, I'd suggest creating a helper like RN's Platform.select, which could look like this:

const deviceLocator = platformSelect({
  ios: this.buttonComponentIOS,
  android: this.buttonComponent
});

Since you're using a class, it could be done once in property initializer or constructor:

class ComponentsScreen {
  element = platformSelect({
    ios: '[label="Button Simple React Native button component."]',
    android: '~Button Simple React Native button component.'
  })

  async checkButtonComponentIsDisplayed() {
    return await Utils.checkElementExistence(element);
  }
}

@@ -0,0 +1,31 @@
const Utils = require('../helpers/utils');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use import instead of require?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
if (process.env.E2E_DEVICE .includes('android')) {
deviceLocator = this.btnOK;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, let's create the platformSelect helper mentioned here: https://github.com/facebook/react-native/pull/35016/files#r1024331245 and refactor

Then Verify that the "Button" header is displayed
When User clicks on the Cancel Application button
Then Verify that the alert box has text: "Your application has been cancelled!"
When User clicks on the OK button
Copy link

@adzironman adzironman Nov 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add here one more Then step e.g.
Then User is on the main screen
The same in second scenario.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed
Then Verify that the "Button" header is displayed has been added

@@ -0,0 +1,4 @@
module.exports = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this repo has a root eslintrc so we can remove this one :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


export const thenVerifyAlertBoxHasText = (then) => {
then(/^Verify that the cancel|submit alert box has text: "(.*)"$/, async (alertBoxType, alertBoxText) => {
switch(alertBoxType) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@pull-bot
Copy link

PR build artifact for faff18a is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for faff18a is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@github-actions
Copy link

github-actions bot commented Nov 17, 2022

Warnings
⚠️ 🔒 package.json - Changes were made to package.json. This will require a manual import by a Facebook employee.

Generated by 🚫 dangerJS against b8350e9

@pull-bot
Copy link

PR build artifact for 192ae42 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for 192ae42 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@mateuszm22 mateuszm22 changed the title Feature/rn tester e2e Feature/Rn-tester-Automation-tests-for-iOS-and-Android-with-Appium-Jest-Cucumber Nov 17, 2022
@mateuszm22 mateuszm22 changed the title Feature/Rn-tester-Automation-tests-for-iOS-and-Android-with-Appium-Jest-Cucumber RNTester: Setup E2E tests for iOS and Android with Appium, Jest and Cucumber Nov 17, 2022
@mateuszm22 mateuszm22 marked this pull request as ready for review November 17, 2022 17:08
@pull-bot
Copy link

PR build artifact for ee7fbb9 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for ee7fbb9 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for a304fc9 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for a304fc9 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for d3e745b is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for d3e745b is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for da78d7c is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

PR build artifact for bc70302 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

pull-bot commented Jan 2, 2023

PR build artifact for d1a238f is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

pull-bot commented Jan 2, 2023

PR build artifact for d1a238f is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

Comment on lines 26 to 30
If you are M1 mac user:
1. Install ffi package `gem install ffi -v '1.15.5' --source 'https://rubygems.org/'`
2. Install pods with new architecture, e.g. using JSC `USE_HERMES=0 arch -x86_64 pod install`
3. Open the generated `RNTesterPods.xcworkspace`.
4. Build the app.
Copy link
Contributor

@kelset kelset Jan 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should not be needed anymore (the ffi workaround)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay i will remove

@@ -0,0 +1,21 @@
Feature: Button component screen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file should not be needed since we don't have cucumber in this PR, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, thanks. fixed

Comment on lines 17 to 22
"babel-jest": "^26.6.3",
"eslint": "^7.32.0",
"jest": "^26.6.3",
"jest-html-reporter": "^3.7.0",
"metro-react-native-babel-preset": "^0.70.3",
"react-test-renderer": "18.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some of these dependencies need to be realigned with the rest of the monorepo

@@ -0,0 +1,80 @@
# Building the app
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're going to need some more docs on the readme, with instructions like how to setup Appium, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is in README-addTestAndExecute

@mateuszm22 mateuszm22 changed the title RNTester: Setup E2E tests for iOS and Android with Appium, Jest and Cucumber RNTester: Setup E2E tests for iOS and Android with Appium and Jest Jan 13, 2023
@kelset
Copy link
Contributor

kelset commented Jan 13, 2023

(cross-reference: second PR here: https://github.com/facebook/react-native/pull/35824/files)

@kelset
Copy link
Contributor

kelset commented Jan 16, 2023

Crossposting here: please check out the comments that were left on the 2nd PR:

as a part of them overlap with mines + a few more are actionable now; a third part need to be handled in the future.

@@ -0,0 +1 @@
put app in this folder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we should change the name of this file to README.txt so that it shows up by default if you navigate to it via ex. GH web ui

import { beforeEach, afterEach, jest } from '@jest/globals';


jest.setTimeout(40000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the timeout is already set to 60000 in jest.config.js, any reason why it's re-set here and it's a different value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, removed this one and keep the value in jest.config.js

path: '/wd/hub',
host: 'localhost',
port: 4723,
waitforTimeout: 30000,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yet another timeout with a different value from 60000 and 40000, let's just set the same one everywhere - or there's a reason why they are different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value has changed

host: 'localhost',
port: 4723,
waitforTimeout: 30000,
logLevel: 'silent',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might want it to be at least error:

Suggested change
logLevel: 'silent',
logLevel: 'error',

See here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 6 to 7
ios: '[label="Button"]',
android: '//android.view.ViewGroup/android.widget.TextView[@text="Button"]',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should be able to rely on the props of the components like here:

const UsernameTextInput = await client.$('~username-textinput');

this will require a bit of work on the RNTester (adding this util and then adding the prop to all components) itself but it will make the whole thing more scalable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

@lukutism lukutism Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use testID and accessibilityLabel ? so xpath will look like this $(//*[@content-desc="Button1" or @name="Button1"]) it will work for iOS and android. But I would use accessibilityLabels/testID $('~Button1') instead of xpath's. Xpaths lookups is really slow :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@kelset kelset left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall general note, per Nick's comment here, it's likely we'll have to add a copyright note at the top of each *.js file as such:

/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

reference here.

(we might not need the @flow @Format refs but we should look into that)

@kelset
Copy link
Contributor

kelset commented Feb 23, 2023

Headsup

Work is now moved here ---> #36267

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
No CLA Authors need to sign the CLA before a PR can be reviewed. Type: Enhancement A new feature or enhancement of an existing feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.