React is a JavaScript library designed to make creating interactive user interfaces painless. When used as a base in the development of single-page or mobile applications, React provides an optimal experience for users by fetching rapidly changing data with ideal performance.
In this guide we will use a React app with Selenium WebDriver and the Python programming language.
Get started
You will need a Username and Authkey to run your tests on CrossBrowserTesting To get yours, sign up for a free trial or purchase a plan.
Install Selenium
Make sure you have Selenium's language bindings for Python installed and ready by running:
sudo pip install selenium
CrossBrowserTesting also recommends requests for RESTful API calls in python. You can install it using pip with following command in your terminal:
sudo pip install requests
Run your first test
Once you have Selenium WebDriver in place, you should be ready to start testing. Copy the following script into your text-editor of choice:
import unittest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import requests
class SeleniumCBT(unittest.TestCase):
def setUp(self):
self.username = "YOUR_USERNAME"
self.authkey = "YOUR_AUTHKEY"
self.api_session = requests.Session()
self.api_session.auth = (self.username,self.authkey)
self.test_result = None
caps = {}
caps['name'] = 'React App Example'
caps['browserName'] = 'Chrome'
caps['version'] = '75'
caps['platform'] = 'Windows'
caps['record_video'] = 'true'
try:
self.driver = webdriver.Remote(
desired_capabilities=caps,
command_executor="http://%s:%[email protected]:80/wd/hub"%(self.username, self.authkey))
except Exception as e:
raise e
def test_CBT(self):
try:
self.driver.implicitly_wait(10)
self.driver.get('https://alik0211.github.io/pokedex/')
search_box = self.driver.find_element_by_xpath('//*[@id="root"]/div/div/input')
search_box.send_keys('vaporeon')
result = self.driver.find_element_by_css_selector('#root > div > ul > li > div > p')
self.assertEqual(result.text, 'vaporeon')
self.test_result = 'pass'
except AssertionError as e:
# log the error message, and set the score to "during tearDown()"
self.api_session.put('https://crossbrowsertesting.com/api/v3/selenium/' + self.driver.session_id + '/snapshots/' + snapshot_hash,
data={'description':"AssertionError: " + str(e)})
self.test_result = 'fail'
raise
self.driver.quit()
# Here we make the api call to set the test's score
# Pass if it passes, fail if an assertion fails, unset if the test didn't finish
if self.test_result is not None:
self.api_session.put('https://crossbrowsertesting.com/api/v3/selenium/' + self.driver.session_id,
data={'action':'set_score', 'score':self.test_result})
if __name__ == '__main__':
unittest.main()
Troubleshooting
You will notice that when testing the React app using iOS configurations that the autocomplete feature behaves in an unexpected manner. This is due to the way Appium fills input fields, which causes React not to detect input. Until the issue is fixed, a work around is provided by adding a few additional lines of code.
webFile = requests.get('https://unpkg.com/react-trigger-change/dist/react-trigger-change.js')
self.driver.execute_script(webFile.text)
self.driver.execute_script("reactTriggerChange(arguments[0]);", search_box)
The first line grabs a js file from this npm package. This file has functions from the React test utilities that allow one to simulate/force an onChange event. The second line injects those functions into the browser/page that your selenium session has loaded, which makes reactTriggerChange()
available for use during that session. The next lines send text to an element, save the locator for that element to a variable, and then run reactTriggerChange()
on that element in order to force React to recognize that a change has occurred.
Let's see how this works when added to our example test:
import unittest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import requests
class SeleniumCBT(unittest.TestCase):
def setUp(self):
self.username = "YOUR_USERNAME"
self.authkey = "YOUR_AUTHKEY"
self.api_session = requests.Session()
self.api_session.auth = (self.username,self.authkey)
self.test_result = None
caps = {}
caps['name'] = 'React App Example'
caps['browserName'] = 'Safari'
caps['deviceName'] = 'iPhone XR Simulator'
caps['platformVersion'] = '12.0'
caps['platformName'] = 'iOS'
caps['record_video'] = 'true'
try:
self.driver = webdriver.Remote(
desired_capabilities=caps,
command_executor="http://%s:%[email protected]:80/wd/hub"%(self.username, self.authkey))
except Exception as e:
raise e
def test_CBT(self):
try:
self.driver.implicitly_wait(10)
self.driver.get('https://alik0211.github.io/pokedex/')
search_box = self.driver.find_element_by_xpath('//*[@id="root"]/div/div/input')
search_box.send_keys('vaporeon')
webFile = requests.get('https://unpkg.com/react-trigger-change/dist/react-trigger-change.js')
self.driver.execute_script(webFile.text)
self.driver.execute_script("reactTriggerChange(arguments[0]);", search_box)
result = self.driver.find_element_by_css_selector('#root > div > ul > li > div > p')
self.assertEqual(result.text, 'vaporeon')
self.test_result = 'pass'
except AssertionError as e:
# log the error message, and set the score to "during tearDown()"
self.api_session.put('https://crossbrowsertesting.com/api/v3/selenium/' + self.driver.session_id + '/snapshots/' + snapshot_hash,
data={'description':"AssertionError: " + str(e)})
self.test_result = 'fail'
raise
self.driver.quit()
# Here we make the api call to set the test's score
# Pass if it passes, fail if an assertion fails, unset if the test didn't finish
if self.test_result is not None:
self.api_session.put('https://crossbrowsertesting.com/api/v3/selenium/' + self.driver.session_id,
data={'action':'set_score', 'score':self.test_result})
if __name__ == '__main__':
unittest.main()
We kept our test brief, but there is so much more you can do with React and Selenium. If you have any questions or concerns, feel free to contact Support.