Skip to content

Instantly share code, notes, and snippets.

@keyserfaty
Last active July 27, 2022 20:32
Show Gist options
  • Save keyserfaty/632bb6f0331dd15f7e886a1494bc1fd0 to your computer and use it in GitHub Desktop.
Save keyserfaty/632bb6f0331dd15f7e886a1494bc1fd0 to your computer and use it in GitHub Desktop.
How to write a simple `Nightwatch` test for a `React` app?

How to write a simple Nightwatch test for a React app?

Nightwatch is a testing tool made in Node and Selenium to test browser apps. Long story short you can set it to navigate (really, truly, navigate) your site to test it as if it was a real person.

After you setup your environment, add your tests and run them Nightwatch will open a browser and start interacting with your site in realtime (you can see the whole thing). It will starting clicking around based on what you told it it should click and test if it encounters what you told it it should encounter.

Ok, so lets get to it!

I'm not gonna focus much in the setting up process (I'm much more interested in the API and the use cases) but this is a summary of what you should do in Mac: (full instructions in the Nightwatch website)

  • Install java (> 7) if you don't have it already (you can check with java -version):

     brew cast install java
    
  • Install nightwatch

      npm i -g nightwatch
    
  • Install selenium:

      brew install selenium-server-standalone
    

After all the installing stuff process you will need to create a configuration file, usually nightwatch.json (an example here).

Ok so now to the fun part!


Creating a test

We will be testing a view that looks like this:

<Modal id="modal-container" show={visible} dialogClassName='inmodal' onHide={() => actions.hideModal()}>
	<Modal.Header id="modal-header">
		<i className='fa fa modal-icon' />
		<Modal.Title>Modal Title</Modal.Title>
	</Modal.Header>
	
	<Modal.Body style={{ textAlign: 'center' }} id="modal-body">
		<span id="modal-canvas">
			<canvas>Some canvas that will of course display nothing like this</canvas>
		</span>
	</Modal.Body>

	<Modal.Footer id="modal-footer">
		<Button id="modal-close-button" bsStyle='default' onClick={() => actions.hideModal()}>
		  Close
		</Button>
		<Button id="modal-download-button" bsStyle='default' onClick={() => actions.hideModal()}>
		  <a href={url} download="canvas.png">
		    Download canvas
		  </a>
		</Button>
	</Modal.Footer>
</Modal>

Ok, so the first thing to take into account is that we have to place our tests in wherever we told the config file you would. So for instance, if our configuration file set something like this:

{
  "src_folders": ["./nightwatch/tests"],
  "output_folder": "./nightwatch/reports",
  "page_objects_path": "./nightwatch/pages",
  ....
}

Then, well, ours test should be in those folders like this (between brackets all the files/folders I'm creating to test this view):

+--- nightwatch
|   +--- tests
|   ------ [modal.tests.js]
|   +--- pages
|   +------ [modal]
|   ---------- [modalPage.js]
|   ---------- [elements.js]
|   +--- reports

So, every time you have to test something: 1) you create a tests file inside tests and a 2) [thing] folder inside pages.

Selecting the elements

So the first thing I think you should do when starting to test something is to create your selectors. Your selectors are basically a list of all the your DOM nodes, all of which you need to take care of.

We are gonna select this elements the same way you would if doing something like document.querySelector('[my pretty selector here]'). So the sintax to select the modal container would be #modal-container.

And where do you put all this? Well in your elements file (which is of course not mandatory but a nice way to keep everything simple and in place):

// elements.js

export const elements = {
  modalContainer: {
    selector: '#modal-container'
  },
  modalCloseButton: {
    selector: '#modal-close-button'
  },
  modalDownloadButton: {
    selector: '#modal-download-button a'
  },
  modal-canvas: {
    selector: '#modal-canvas canvas'
  }
};

A little sintax explanation:

You will be selecting a DOM node from the DOM (or the virtual DOM in this case taking into consideration that we are in React) and you would assign it a variable name. So:

// ...stuff
modalContainer: {
  selector: '#modal-container'
},

So there the element is the #modal-container and the variable name we are assigning to it is modalContainer. We will use this var name later to perform actions onto this element.

Writing the tests

So with all our selectors in place we need to call them somewhere so we can start using them. Lets open our modalPage.js an import them there like this:

import { elements } from './elements';

const modalsCommands = {
  modal () {}
};

export default {
  commands: [modalsCommands],
  elements
};

I'm getting a little ahead of my self here but in this file we will also need to export an object with two props: commands and elements. commands is an array that contains modalsCommands, an object that we will define.


A little on modalsCommands: Imagine you had a view with a form and that you needed to tests a million edge cases as its usually the case with forms. You would need to test, for instance, user creation, wrong password, user login, etc...

So in this case, when you do have a lot of things to test on a single view, you are going to place all of those tests nicely inside a function inside modalsCommands (or similar), like this:

const modalsCommands = {
   userCreation () {},
   wrongPassword () {},
   userLogin () {},
};

So then from your modal.tests.js file you can call each one of them separately.


Back to the magic!

We are gonna setup our modal.tests.js really fast so we can go to the actual testing. The whole point of this file is to do three things (I'm sure it can do a lot more but this is the scope of my current knowledge):

  1. Set up a reference name for this tests only

  2. Set what happens before the tests start

  3. Create the tests.

Basic structure of the file: (yes, I'm running out of h1, h2, h3.. tags to set subtitles here)

export default {
  tags: ['modal'],
  beforeEach: browser => {    
  },

  'The text that describes what the test is doing': client => {
  },
};

So the first thing we set is a tag name (later we are going to run nightwatch with this tag name and is gonna execute only this tests (useful when working in an app with a lot of tests already).

Now to the beforeEach section:

beforeEach: browser => {
  const GLOBALS = browser.globals;
  browser
  // The path where we want the test to start (login in my case)
    .url(GLOBALS.baseUrl + '/login')

// Maybe you need to execute some stuff before starting
// Removing tokens and stuff. Read the full docs for all the
// available methods
    .execute(function () {});
},

And now to the testing part!:

// ...
'Modal should display and buttons should work': client => {
  
},

// TO BE CONTINUED..

@soobhhann
Copy link

That's great thank u for this help hope to continued

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment