diff --git a/packages/rn-tester-e2e/README-addTestAndExecute.md b/packages/rn-tester-e2e/README-addTestAndExecute.md index d18f2eb2075aee..aac2ef3afed6a5 100644 --- a/packages/rn-tester-e2e/README-addTestAndExecute.md +++ b/packages/rn-tester-e2e/README-addTestAndExecute.md @@ -2,9 +2,9 @@ 1. Create a feature file `(rn-tester-e2e/test/features)` - GivenWhenThen Gherkin syntax 2. **OPTIONAL -** Create a screen object or extend the existing one (depends on the test scope) - `rn-tester-e2e/test/screenObjects` - map screen elements for iOS and Android -3. Create a step file `(rn-tester-e2e/test/steps)` - import used screen objects, create execution code of GivenWhenThen steps from feature file -4. Create a runner file `(rn-tester-e2e/test/runners)` - import steps from step3 and create test scenarios -5. Update `(rn-tester-e2e/e2e-config.js)` with proper cababilities of your emulator +3. **OPTIONAL -** Add another common step in `rn-tester-e2e/test/common_steps/common.steps.js` +4. Create a runner file `(rn-tester-e2e/test/runners)` - import steps and screen objects from point 2 and 3. Create test scenarios +5. Update `(rn-tester-e2e/e2e-config.js)` with proper capabilities of your emulator # How to execute a test 1. Open new Terminal -> navigate to the react-native path -> open Metro by typing @@ -16,7 +16,14 @@ or 2. Open second terminal -> navigate to the react-native/packages/rn-tester-e2e -> MAKE SURE YOUR APPIUM HAS UIAUTOMATOR2 AND XCUITEST INSTALLED! type +>npm install appium@2.0.0-beta.40 -g + +>appium driver install uiautomator2 + +>appium driver install xcuitest + >appium --base-path /wd/hub + 3. Open third terminal -> navigate to the react-native/packages/rn-tester-e2e -> run all tests by typing >npm run ios diff --git a/packages/rn-tester-e2e/README-describedAllFoldersAndFiles.md b/packages/rn-tester-e2e/README-describedAllFoldersAndFiles.md index dc8df2a6fa2727..d09ce554ae8266 100644 --- a/packages/rn-tester-e2e/README-describedAllFoldersAndFiles.md +++ b/packages/rn-tester-e2e/README-describedAllFoldersAndFiles.md @@ -1,23 +1,20 @@ # Description of all folders and files in rn-tester-e2e # folders 🗂 -## common_steps 📁 -One function (step) per file. Common, reusable steps should be added there +## common_steps 🪜 +Common steps reusable between different features files ## features 🥒 Cucumber feature files. GivenWhenThen Gherkin syntax. One feature per screen/functionality ## helpers 🧑🏻‍🚒 -Utils file with generic, simple steps +Utils file with generic, simple actions and methods ## runners 🏃🏽‍♀️ -Runner file which combines feature file and steps file. Runner file imports steps file and declares step functions in the same order as in the feature file (FUNCTION STEP LOGIC IS NOT IMPLEMENTED HERE!) +Runner file which combines feature file and steps file. Runner file imports steps file and declares step functions in the same order as in the feature file ## screenObjects 📱 -Screen object files based on Page Object Pattern. One file defines all neccessary elements to interact with. These elements are defined as screen class variables, they are used by the steps file - -## steps 🪜 -Steps file imports screen object (with the same name). Step files define one screen per one file. Step file defines actions which can be performed on this specific page +Screen object files based on Page Object Pattern. One file defines all necessary elements to interact with. These elements are defined as screen class variables, they are used by the steps file # root files 📄 ## e2e-config.js @@ -27,4 +24,7 @@ Android and iOS emulator/physical device configuration, process.env.E2E_device g Global jest config setup - such as timeout, test runner path ## jest.setup.js -Jest and wdio setup file \ No newline at end of file +Jest and wdio setup file + +## package.json +all external dependencies and project parameters \ No newline at end of file diff --git a/packages/rn-tester-e2e/e2e-config.js b/packages/rn-tester-e2e/e2e-config.js index 334244960b1d72..7225d988bafe3c 100644 --- a/packages/rn-tester-e2e/e2e-config.js +++ b/packages/rn-tester-e2e/e2e-config.js @@ -4,21 +4,21 @@ const path = require('path'); let capabilities; const android = { - platformName: 'Android', - platformVersion: '13.0', - deviceName: 'Pixel 6 API 33', - app: path.join(process.cwd(), '/apps/rn-tester.apk'), - automationName: 'UiAutomator2', - newCommandTimeout: 240, + 'platformName': 'Android', + 'appium:platformVersion': '', + 'appium:deviceName': '', + 'appium:app': path.join(process.cwd(), '/apps/RNTester.apk'), + 'appium:automationName': 'uiautomator2', + 'appium:newCommandTimeout': 240, }; const ios = { 'platformName': 'iOS', - 'appium:platformVersion': '16.0', - 'appium:deviceName': 'iPhone 14 Pro Max', + 'appium:platformVersion': '', + 'appium:deviceName': '', //bundleId: 'org.reactjs.native.example.TestForE2E', 'appium:automationName': 'XCUITest', - 'appium:app': path.join(process.cwd(), '/apps/rn-tester.app'), + 'appium:app': path.join(process.cwd(), '/apps/RNTester.app'), }; if (!process.env.E2E_DEVICE) { diff --git a/packages/rn-tester-e2e/test/common_steps/common.steps.js b/packages/rn-tester-e2e/test/common_steps/common.steps.js new file mode 100644 index 00000000000000..38280d1ccd072b --- /dev/null +++ b/packages/rn-tester-e2e/test/common_steps/common.steps.js @@ -0,0 +1,14 @@ +import { driver } from '../../jest.setup.js'; + +// Common steps reusable between different features +export const userIsOnMainScreen = (given) => { + given('User is on the main screen', async () => { + await driver.pause(2000); + }); +}; + +export const clickOkButton = (given) => { + given('User clicks on the OK button', async () => { + await driver.pause(2000); + }); +}; diff --git a/packages/rn-tester-e2e/test/common_steps/givenUserOnMainPage.steps.js b/packages/rn-tester-e2e/test/common_steps/givenUserOnMainPage.steps.js deleted file mode 100644 index dc4d6f9699e79d..00000000000000 --- a/packages/rn-tester-e2e/test/common_steps/givenUserOnMainPage.steps.js +++ /dev/null @@ -1,7 +0,0 @@ -import { driver } from '../../jest.setup.js'; - -export const givenUserOnMainPage = (given) => { - given('User is on the main screen', async () => { - await driver.pause(2000); - }); -}; diff --git a/packages/rn-tester-e2e/test/features/buttonComponentScreen.feature b/packages/rn-tester-e2e/test/features/buttonComponentScreen.feature index 18966c1bcd3e27..66993077062274 100644 --- a/packages/rn-tester-e2e/test/features/buttonComponentScreen.feature +++ b/packages/rn-tester-e2e/test/features/buttonComponentScreen.feature @@ -7,8 +7,7 @@ Feature: Button component screen Then Verify that the "Button" header is displayed When User clicks on the Cancel Application button Then Verify that the cancel alert box has text: "Your application has been cancelled!" - When User clicks on the OK button - Then Verify that the "Button" header is displayed + And User clicks on the OK button Scenario: Submit Button Given User is on the main screen @@ -17,5 +16,4 @@ Feature: Button component screen Then Verify that the "Button" header is displayed When User clicks on the Submit Application button Then Verify that the submit alert box has text: "Your application has been submitted!" - When User clicks on the OK button - Then Verify that the "Button" header is displayed \ No newline at end of file + And User clicks on the OK button \ No newline at end of file diff --git a/packages/rn-tester-e2e/test/runners/buttonComponentScreenRunner.js b/packages/rn-tester-e2e/test/runners/buttonComponentScreenRunner.js index af3e4cca53018f..3da267c415a57c 100644 --- a/packages/rn-tester-e2e/test/runners/buttonComponentScreenRunner.js +++ b/packages/rn-tester-e2e/test/runners/buttonComponentScreenRunner.js @@ -1,46 +1,86 @@ import { defineFeature, loadFeature } from 'jest-cucumber'; -import { givenUserOnMainPage } from '../common_steps/givenUserOnMainPage.steps'; -import * as steps from '../steps/buttonComponentScreen.steps'; +import { userIsOnMainScreen, clickOkButton } from '../common_steps/common.steps'; +import componentsScreen from '../screenObjects/components.screen.js'; +import buttonComponentScreen from '../screenObjects/buttonComponent.screen.js'; -Object.entries(steps).forEach(([name, exported]) => window[name] = exported); +// Object.entries(steps).forEach(([name, exported]) => window[name] = exported); const feature = loadFeature('test/features/buttonComponentScreen.feature'); +//Methods used more than once in the feature +const buttonComponentShouldBeDisplayed = (then) => { + then('Verify that the Button component is displayed', async () => { + expect(await componentsScreen.checkButtonComponentIsDisplayed()).toBeTruthy(); + }); +}; + +const clickOnButtonComponent = (when) => { + when('User clicks on the Button component', async () => { + await componentsScreen.clickButtonComponent(); + }); +}; + +const buttonHeaderShouldBeDisplayed = (then) => { + then(/^Verify that the "(.*)" header is displayed$/, async (headerScreenName) => { + switch (headerScreenName) { + case 'Button': + expect(await buttonComponentScreen.checkButtonsScreenIsDisplayed()).toBeTruthy(); + break; + // here you can add more similar assertions + default: throw new Error(`Wrong parameter provided. There is no such case as: ${headerScreenName}`); + } + }); +}; + +const alertBoxShouldHaveText = (then) => { + then(/^Verify that the cancel|submit alert box has text: "(.*)"$/, async (alertBoxType, alertBoxText) => { + switch (alertBoxType) { + case 'cancel': + expect(await buttonComponentScreen.getCancelAlertText()).toContain(alertBoxText); + break; + case 'submit': + expect(await buttonComponentScreen.getSubmitAlertText()).toContain(alertBoxText); + break; + } + }); +}; + defineFeature(feature, (test) => { test('Cancel Button', ({ given, when, then }) => { - givenUserOnMainPage(given); + userIsOnMainScreen(given); - thenVerifyThatTheButtonComponentIsDisplayed(then); + buttonComponentShouldBeDisplayed(then); - whenUserClicksOnTheButtonComponent(when); + clickOnButtonComponent(when); - thenVerifyThatTheButtonHeaderIsDisplayed(then); + buttonHeaderShouldBeDisplayed(then); - whenUserClicksOnTheCancelApplicationButton(when); + //method which is used only once in whole feature + when(/^User clicks on the Cancel Application button$/, async () => { + await buttonComponentScreen.clickCancelApplication(); + }); - thenVerifyAlertBoxHasText(then); + alertBoxShouldHaveText(then); - whenUserClicksOnTheOKButton(when); - - thenVerifyThatTheButtonHeaderIsDisplayed(then); + clickOkButton(when); }); test('Submit Button', ({ given, when, then }) => { - givenUserOnMainPage(given); - - thenVerifyThatTheButtonComponentIsDisplayed(then); + userIsOnMainScreen(given); - whenUserClicksOnTheButtonComponent(when); + buttonComponentShouldBeDisplayed(then); - thenVerifyThatTheButtonHeaderIsDisplayed(then); + clickOnButtonComponent(when); - whenUserClicksOnTheSubmitApplicationButton(when); + buttonHeaderShouldBeDisplayed(then); - thenVerifyAlertBoxHasText(then); + when(/^User clicks on the Submit Application button$/, async () => { + await buttonComponentScreen.clickCancelApplication(); + }); - whenUserClicksOnTheOKButton(when); + alertBoxShouldHaveText(then); - thenVerifyThatTheButtonHeaderIsDisplayed(then); + clickOkButton(when); }); - }); +}); diff --git a/packages/rn-tester-e2e/test/screenObjects/buttonComponent.screen.js b/packages/rn-tester-e2e/test/screenObjects/buttonComponent.screen.js index 3cbce504e2f191..383e5186b988c7 100644 --- a/packages/rn-tester-e2e/test/screenObjects/buttonComponent.screen.js +++ b/packages/rn-tester-e2e/test/screenObjects/buttonComponent.screen.js @@ -40,7 +40,7 @@ class ButtonComponentScreen { async checkButtonsScreenIsDisplayed() { - return await Utils.getElementText(this.buttonScreenElement); + return await Utils.checkElementExistence(this.buttonScreenElement); } async clickSubmitApplication() { diff --git a/packages/rn-tester-e2e/test/steps/buttonComponentScreen.steps.js b/packages/rn-tester-e2e/test/steps/buttonComponentScreen.steps.js deleted file mode 100644 index 90e9f2cb8e654c..00000000000000 --- a/packages/rn-tester-e2e/test/steps/buttonComponentScreen.steps.js +++ /dev/null @@ -1,52 +0,0 @@ -import componentsScreen from '../screenObjects/components.screen.js'; -import buttonComponentScreen from '../screenObjects/buttonComponent.screen.js'; -import { expect } from '@jest/globals'; - -export const thenVerifyThatTheButtonComponentIsDisplayed = (then) => { - then('Verify that the Button component is displayed', async () => { - expect(await componentsScreen.checkButtonComponentIsDisplayed()).toBeTruthy(); - }); -}; - -export const whenUserClicksOnTheButtonComponent = (when) => { - when('User clicks on the Button component', async () => { - await componentsScreen.clickButtonComponent(); - }); -}; - -export const thenVerifyThatTheButtonHeaderIsDisplayed = (then) => { - then(/^Verify that the "(.*)" header is displayed$/, async (headerScreenName) => { - expect(await buttonComponentScreen.checkButtonsScreenIsDisplayed()).toContain(headerScreenName); - }); -}; - -export const whenUserClicksOnTheCancelApplicationButton = (when) => { - when('User clicks on the Cancel Application button', async () => { - await buttonComponentScreen.clickCancelApplication(); - }); -}; - -export const thenVerifyAlertBoxHasText = (then) => { - then(/^Verify that the cancel|submit alert box has text: "(.*)"$/, async (alertBoxType, alertBoxText) => { - switch (alertBoxType) { - case 'cancel': - expect(await buttonComponentScreen.getCancelAlertText()).toContain(alertBoxText); - break; - case 'submit': - expect(await buttonComponentScreen.getSubmitAlertText()).toContain(alertBoxText); - break; - } - }); -}; - -export const whenUserClicksOnTheOKButton = (when) => { - when('User clicks on the OK button', async () => { - await buttonComponentScreen.clickOkButton(); - }); -}; - -export const whenUserClicksOnTheSubmitApplicationButton = (when) => { - when('User clicks on the Submit Application button', async () => { - await buttonComponentScreen.clickSubmitApplication(); - }); -};