With a long list of end-to-end (e2e) test frameworks available, it’s hard to know what you should use. Cypress and Selenium lead the market as the most commonly used options, but it is also appium testing of mobile applications, Puppeteer to automate tasks in Chrome and Protractor AngularJS applications just to name a few.

Recently, a newcomer has joined the package: TestProject, a free, open source testing automation platform for e2e testing that helps simplify network, mobile, and API testing. The TestProject SDK has language support for Java, C #, Python and the latest JavaScript.

In this article we will show you how we can use TestProject JavaScript OpenSDK test React Is as a test frame.

Are you ready to get started?

Application overview

Let’s start by looking at the test application. This app is relatively simple: just a simple request form where the user can enter their first name, last name, and email address.

Demo application: request form

If the form is submitted without being properly completed, error messages will be displayed below the incorrect message.

Demonstration application: incorrect input

Demonstration application: incorrect input

When the form is successfully submitted, the application will display a confirmation text.

Demo application: filling out a form

Demo application: filling out a form

Demo application: confirmation page

Demo application: confirmation page

Simple enough, right? If you want to see a demo in action, you can find the Hosted Demo app here or view source code in GitHub.

Now let’s see how the application was made.

Creating a React application

As stated above, this application is written in React. To simplify the boiler code and development tools I used create-respond-application tool to launch the application.

npx create-react-app testproject-demo

When the skeleton application was created, I deleted the default content of the application and wrote a simple form component in a file called RequestForm.js. Here is the request code, which is completely reproduced:

import React, { useState } from 'react'
import './RequestForm.css'

export const RequestForm = () => {
  const [firstName, setFirstName] = useState('')
  const [lastName, setLastName] = useState('')
  const [email, setEmail] = useState('')

  const handleFirstNameChange = e => {
    setFirstName(e.target.value)
  }

  const handleLastNameChange = e => {
    setLastName(e.target.value)
  }

  const handleEmailChange = e => {
    setEmail(e.target.value)
  }

  const [firstNameError, setFirstNameError] = useState('')
  const [lastNameError, setLastNameError] = useState('')
  const [emailError, setEmailError] = useState('')

  const [submitted, setSubmitted] = useState(false)

  const handleSubmit = e => {
    e.preventDefault()

    setFirstNameError(firstName ? '' : 'First Name field is required')
    setLastNameError(lastName ? '' : 'Last Name field is required')
    setEmailError(email ? '' : 'Email field is required')

    if (firstName && lastName && email) {
      setSubmitted(true)
    }
  }

  return submitted ? (
    <p id="submissionConfirmationText">
      Thank you! We will be in touch with you shortly.
    </p>
  ) : (
    <form className="requestForm" onSubmit={handleSubmit}>
      <div className={`formGroup${firstNameError ? ' error' : ''}`}>
        <label htmlFor="firstName">First Name</label>
        <input
          name="firstName"
          id="firstName"
          data-testid="firstName"
          value={firstName}
          onChange={handleFirstNameChange}
        />
      </div>
      {firstNameError && (
        <p className="errorMessage" id="firstNameError">
          {firstNameError}
        </p>
      )}
      <div className={`formGroup${lastNameError ? ' error' : ''}`}>
        <label htmlFor="lastName">Last Name</label>
        <input
          name="lastName"
          id="lastName"
          data-testid="lastName"
          value={lastName}
          onChange={handleLastNameChange}
        />
      </div>
      {lastNameError && (
        <p className="errorMessage" id="lastNameError">
          {lastNameError}
        </p>
      )}
      <div className={`formGroup${emailError ? ' error' : ''}`}>
        <label htmlFor="email">Email</label>
        <input
          type="email"
          name="email"
          id="email"
          data-testid="email"
          value={email}
          onChange={handleEmailChange}
        />
      </div>
      {emailError && (
        <p className="errorMessage" id="emailError">
          {emailError}
        </p>
      )}
      <button type="submit" id="requestDemo">
        Request Demo
      </button>
    </form>
  )
}

As you can see, we have an action component that displays three entries for a user’s first name, last name, and email address. There is a “Request Demo” button at the bottom of the form. When the form is submitted, error messages are displayed if the entries are incorrect, and a confirmation message is displayed if the form is submitted successfully.

That’s really all there is to the app. Now, the fun part. How can we configure end-to-end tests with TestProject?

Getting Started with TestProject

To begin with, we must first create a free TestProject account. After that we can download TestProject Agent. There are options to either download the agent to the desktop or the Docker. Which one you choose is up to you, but I decided to download the desktop app for Mac. Then you have to register your representative link your agent to your TestProject account.

Next we create developer id used in our project. When we have a developer ID, we create .env file to the root directory of the project and add the following line of code to store our ID TP_DEV_TOKEN environmental variable:

TP_DEV_TOKEN=<YOUR DEV TOKEN HERE>

Note that we are telling Git .gitignore file ignored .envfile so that our IDs or other environmental secrets are not committed to version control and are inadvertently shared with others.

Finally, we need to install a couple of npm packages with the name devDependencies to use TestProject JavaScript OpenSDK in our application:

yarn add --dev @tpio/javascript-opensdk selenium-webdriver

With it, we have created most of the platform to start using TestProject with our e2e tests.

The determination is

Next, we need to determine Jest. Because we used the create-respond application to launch our application, our project uses reaction series run Jest and React Testing Library with some default settings. However, it would be nice if we can configure Jest and add a few more npm scripts so that the unit and e2e tests can be run separately.

To do this, I added the following npm scripts to my “scripts” section package.json file. Each of them includes some specific Jest CLI configuration options:

"scripts": {
  ...other scripts here
  "start": "react-scripts start",
  "test:e2e": "wait-on http://localhost:3000/testproject-demo/build/ && react-scripts test --testPathPattern="(.|/)e2e.(test|spec).[jt]sx?$" --testTimeout=30000 --runInBand --watchAll=false",
  "test:e2e:ci": "run-p start test:e2e",
  "test:e2e:watch": "wait-on http://localhost:3000/testproject-demo/build/ && react-scripts test --testPathPattern="(.|/)e2e.(test|spec).[jt]sx?$" --testTimeout=30000 --runInBand",
  "test:unit": "react-scripts test --testPathPattern="(.|/)unit.(test|spec).[jt]sx?$" --watchAll=false",
  "test:unit:coverage": "react-scripts test --testPathPattern="(.|/)unit.(test|spec).[jt]sx?$" --watchAll=false --coverage",
  "test:unit:watch": "react-scripts test --testPathPattern="(.|/)unit.(test|spec).[jt]sx?$""
},

That’s a lot to take! Let’s break these commands and highlight some of the key passages in this code.

First we see start manuscript. It’s easy enough: it uses our app locally in development mode. This is important because e2e tests require the application to work properly.

Next we will see test:e2e manuscript. This command waits for the application to run locally on port 3000 before attempting to run tests. Then it uses react-scripts test command to run application tests, but there are several Jest CLI configuration options. testPathPattern the option only tells Jest that the tests are over e2e.test.js (and a few other variations). testTimeout The option raises the default Jest time, which is 5 seconds per test, to 30 seconds per test, because performing e2e tests takes a little longer than with simple tests. runInBand the option tells Jest that the test files are run in series and not in parallel because only one TestProject agent is installed on our machine. And finally watchAll=false This option makes the tests not run in “watch” mode, which is the default setting for Jest with responsive scripts. Oh, that was a lot!

The third script is test:e2e:ci. This command is a combination start and test:e2e commands to simplify the testing process. To use the original test:e2e command, we must first use the application locally. So we have to drive first yarn start and then run yarn test:e2e. It’s not a big deal, but now we have an even simpler process where we can just run yarn test:e2e:ci both launch the application and run e2e tests.

The fourth manuscript, test:e2e:watch, is very similar to test:e2e script, but run the tests in “watch” mode if you want the tests to run in the background as you make changes to your application.

The last three scripts are used to perform unit tests. test:unit script performs unit tests with the Jest and React Testing Library and searches only for ending tests unit.test.js (and a few other variations). test:unit:coverage the script performs these same unit tests, but also includes a test report. And finally test:unit:watch script performs unit tests in clock mode.

This may seem like a lot of information to take, but here’s a guarantee that we’ve now created several useful npm scripts that allow us to easily run our unit and e2e tests with short and simple commands. All the difficult assembly work is out of the way, so now we can focus on writing the actual tests.

Writing tests with JavaScript OpenSDK

Jest and TestProject are now defined for our project, so we are ready to write our first e2e test. End-to-end tests typically focus on the critical workflows of an application, represented by user journeys.

With regard to the request form, I can think of two important user journeys: when a user tries to submit an incorrect form and when a user successfully submits a duly completed form. Write an e2e test for each workflow.

Our perfect App.e2e.test.js the file looks like this:

{driver = wait for new build tool () .forBrowser (‘chrome’) .withProjectName (‘TestProject Demo’) .withJobName (‘Request Form’) .build ()}) afterEach (async () => {waiting for driver.quit ( )}) it (‘let the user submit the form when it is filled in correctly’, async () => {wait driver.get (testUrl) wait driver.findElement (By.css (‘# firstname’)). sendKeys (‘ John ‘) is waiting for driver.findElement (By.css (‘ # lastName ‘)). SendKeys (‘ Doe ‘) is waiting for driver.findElement (By.css (‘ # email ‘)). SendKeys (‘john.doe@email. com ‘) wait driver.findElement (By.css (‘ # requestDemo ‘)). click () wait driver .findElement (By.css (‘ # submittedConfirmationText ‘)) .isDisplayed ()}) it (‘ prevents the user from submitting the form , when not filled in properly ‘, async () => {wait driver.get (testUrl) waiting driver.findElement (By.css (‘ # requestDemo ‘)) Click () wait driver.findElement (By. css ( ‘# firstNameError’)). isDisplayed () waiting for driver.findElement (By.css (‘# las tNameError ‘)). isDisplayed () is waiting for driver.findElement (By.css (‘# emailError’)). isDisplayed ()})}) “d ata-lang =” text / javascript “>

import { By } from 'selenium-webdriver'
import { Builder } from '@tpio/javascript-opensdk'

describe('App', () => {
  const testUrl="http://localhost:3000/testproject-demo/build/"

  let driver

  beforeEach(async () => {
    driver = await new Builder()
      .forBrowser('chrome')
      .withProjectName('TestProject Demo')
      .withJobName('Request Form')
      .build()
  })

  afterEach(async () => {
    await driver.quit()
  })

  it('allows the user to submit the form when filled out properly', async () => {
    await driver.get(testUrl)
    await driver.findElement(By.css('#firstName')).sendKeys('John')
    await driver.findElement(By.css('#lastName')).sendKeys('Doe')
    await driver.findElement(By.css('#email')).sendKeys('john.doe@email.com')
    await driver.findElement(By.css('#requestDemo')).click()

    await driver
      .findElement(By.css('#submissionConfirmationText'))
      .isDisplayed()
  })

  it('prevents the user from submitting the form when not filled out properly', async () => {
    await driver.get(testUrl)
    await driver.findElement(By.css('#requestDemo')).click()

    await driver.findElement(By.css('#firstNameError')).isDisplayed()
    await driver.findElement(By.css('#lastNameError')).isDisplayed()
    await driver.findElement(By.css('#emailError')).isDisplayed()
  })
})

In our first test, we make sure that the user can submit the form successfully. We navigate to the URL of our application, please use sendKeysmethod to enter text in the three input fields, and then click the Send button. We then wait for the confirmation text to appear on the screen to confirm that the transmission was successful.

Note that all selectors look just like regular selenium selectors. You can usually find elements with the CSS switches or the XPath selector.

In our second test, we make sure that the user is prevented from submitting the form when there are invalid entries on the page. We first go to the URL of our application and then immediately click the Submit button without filling in any input fields. We then make sure that three error messages are displayed on the screen.

Also note that we’ve picked up and unpacked some of the shared test setup beforeEach and afterEach blocks. in beforeEach block, we will create your web browser for Chrome. in afterEach Block the controller.

Performing E2E tests

Here’s a moment of truth: Trying to perform end-to-end tests. We run in our terminal yarn test:e2e:ci Launch the application and run the e2e tests. And… these two tests pass! You should see the app open in Chrome, see the steps for each test you run, and see the test results back on your terminal:

Let's take our e2e test at the terminal

Let’s take our e2e test at the terminal

TestProject even offers your own free, built-in report views, as well as local HTML and PDF reports, so you can see test results in your browser. This is perfect when looking at tests performed as part of a CI tube. Here are my reports after running the test package twice:

TestProject report control panel

TestProject report control panel

Conclusion

Well, we did it! We successfully wrote and performed end-to-end tests using React, Jest, and TestProject JavaScript OpenSDK. Mission accomplished.

The exciting thing is that this is just the tip of the iceberg. TestProject is full of other hidden gems, such as ability write tests directly in the browser using the graphical user interface, several add-ons – tests required in general, and integrations with applications like Slack for sending test report notifications.

Who knows what the future holds for the world of end-to-end testing automation, but TestProject is certainly a platform worth keeping an eye on.

.

LEAVE A REPLY

Please enter your comment!
Please enter your name here