DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Introduction to Building Desktop Applications With Electron
  • Testing Serverless Functions
  • Microservices Testing: Key Strategies and Tools
  • How to Become a DevOps Engineer

Trending

  • How to Merge HTML Documents in Java
  • What’s Got Me Interested in OpenTelemetry—And Pursuing Certification
  • Monoliths, REST, and Spring Boot Sidecars: A Real Modernization Playbook
  • Simpler Data Transfer Objects With Java Records
  1. DZone
  2. Coding
  3. Frameworks
  4. Write Automated Tests for Electron With Spectron, Mocha, and Chai

Write Automated Tests for Electron With Spectron, Mocha, and Chai

Automated testing is a key part of any truly Agile environment. We take a look at how to use these technologies to achieve testing excellence.

By 
Dr. Matthias Sommer user avatar
Dr. Matthias Sommer
·
Oct. 04, 17 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
28.8K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, you will learn how to test your Electron-based desktop application with Mocha, Chai, and Spectron. You will learn how to set up the test environment and run automated integration or E2E tests with Spectron, Mocha, and Chai. Furthermore, a short introduction to CSS selectors is given.

1. Cross-Platform Apps With Electron

Electron allows us to write cross-platform apps for Windows, Linux, and Mac based on the same code base. Thereby, we develop our desktop applications using HTML, CSS, and Javascript (or Typescript). Finally, we package our Electron app with electron-packager or electron-builder and ship it as OS-specific bundle (.app, .exe, etc.). The application itself runs on Chromium. In this article, I will give an introduction on how to setup the test environment for automated end-to-end test or integration tests for your Electron application.

2. Automated Test Environment

Mocha is a JavaScript test framework which runs on Node.js. Mocha allows us to use any assertion library we like. In the following, I will use Chai with should-style assertions.

Chai is a BDD/TDD assertion library for Node.js. Furthermore, we will use Chai as Promised which extends Chai for asserting facts about promises. Thereby, we can transform any Chai assertion into one that acts on a promise.

Spectron is an open source framework for easily writing automated integrations and end-to-end tests for Electron. It provides capabilities for navigating on web pages, simulating user input, and much more. It also simplifies the setup, running, and tearing down of the test environment for Electron.

Through Spectron, you have the entire Electron API and Chromium API available within your tests. Thereby, we can test our Electron apps using ChromeDriver and WebdriverIO.

Finally, we can also run the tests on continuous integration services and build servers, such as Travis and Jenkins.

3. Environment Setup

First, we install Spectron via npm as development dependency:

npm install --save-dev spectron

You may want to install chai and chai-as-promised as well.

npm install --save-dev chai
npm install --save-dev chai-as-promised

Chai is a BDD/TDD assertion library for node and Chai-as-promised extends it with assertions about promises.

Also install @types/mocha, electron-chromedriver, mocha, and spectron as dev dependencies.

Finally, your devDependencies in your package.json should look like this (perhaps with newer version numbers):

"devDependencies": {
   "@types/mocha": "2.2.43",
   "chai": "4.1.2",
   "chai-as-promised": "7.1.1",
   "electron-chromedriver": "1.7.1",
   "mocha": "3.5.3",
   "spectron": "3.7.2"
}

Setting Up the Mocha Test Runner

Next, we go to our package.json file to set up the test commands. A minimal configuration calls the Mocha test runner without any parameter settings.

"scripts": {
    "test": "mocha"
}

When we execute npm run test, Mocha is executed looking for files defining tests (can be a unit test or an integration test).

The following command tells Mocha to only run tests contained at a specific location. The grep command tells it to only consider files with a certain file name. The --watch parameter runs tests on changes to JavaScript files in the defined directory and once initially.

mocha {{folder/with/tests}} --grep {{^regex$}} --watch

I have created two scripts. One is for running all integration tests in the test folder. The other one runs only one specific test every time the test or the class under test is changed.

test:all runs Mocha, with the following conditions:

  • With mocha-jenkins-reporter as the reporter.
  • Sets the timeout to 20 seconds.
  • Tells Mocha to only look for tests in the src/test folder within files whose names start with test- and end with .js
"test:all": "mocha -R mocha-jenkins-reporter --timeout 20000 \"./src/test/**/*test-*.js\""

test:one tells Mocha to watch for code changes and to re-run the test. We use grep to run only tests where the name fits the given string.

"test:one": "mocha --watch -u bdd \"./src/test/**/test-*.js\" --grep \"test-login-form\""

Setting Up Spectron

I have written an extra class where I have a function to launch Spectron which then creates a new Application class that, when configured, starts and stops our Electron application via app.start() and app.stop().

Therefore, we have to specify the path to the electron batch file as well as to our dist folder. Here, I am setting the start timeout to 20 seconds. By setting the property chromeDriverLogPath, Chromedriver is activated to execute logging.

initialiseSpectron() {
   let electronPath = path.join(__dirname, "../../node_modules", ".bin", "electron");
   const appPath = path.join(__dirname, "../../dist");
   if (process.platform === "win32") {
       electronPath += ".cmd";
   }

   return new Application({
       path: electronPath,
       args: [appPath],
       env: {
           ELECTRON_ENABLE_LOGGING: true,
           ELECTRON_ENABLE_STACK_DUMPING: true,
           NODE_ENV: "development"
       },
       startTimeout: 20000,
       chromeDriverLogPath: '../chromedriverlog.txt'
  });
}

Have a look in the application API of Spectron to find out more about the configuration.

4. Writing Automated Tests

After setting up our test environment, we will write an integration test using Mocha and Chai. I am going to write a test for a login form written in Angular 4 using reactive forms which I have presented in this article.

We create a new JavaScript class in our test folder which we call test-login-form.js. First, we import all libraries and call our Spectron helper class.

const testhelper = require("./spectron-helper");
const app = testhelper.initialiseSpectron();

const chaiAsPromised = require("chai-as-promised");
const chai = require("chai");
chai.should();
chai.use(chaiAsPromised);

Here, I am using the should style which allows me to chain assertions by starting with the should property. You can also use the expect or the assert style.

Life Cycle Hooks

Similar to JUnit, Mocha offers functions for initial setup, cleaning, and tear down actions. These life cycle hooks are called before(), beforeEach(), after(), and afterEach().

We use the before hook to set up Chai-as-promised and to start our Electron application via Spectron.

before(function () {
   chaiAsPromised.transferPromiseness = app.transferPromiseness;
   return app.start();      
});

The after function is used to tear down everything and to stop the application.

after(function () {
   if (app && app.isRunning()) {
       return app.stop();
   }
});

Defining Test Beds and Tests

We define a test called Login via the following: 

describe("Login", function () { 
   it('open window', function () {
   }
});

Initially, I would test if the application was successfully initialized. Thereby, a window should be created. We test this via:

it('open window', function () {
   return app.client.waitUntilWindowLoaded().getWindowCount().should.eventually.equal(1);
});

Remember, app is our Electron application. Client is the renderer process. This simple example also shows how Chai-as-promised can be used with Spectron. By appending should.eventually.equal(1) we create a promise which is resolved when a window is loaded before the default timeout of five seconds is over. Otherwise, the promise is rejected and the test fails.

Simulate Actions and Select Elements With CSS Selectors

We can also simulate clicks and the filling out of forms.

it("go to login view", function () {
    return app.client.element('#sidebar').element("a*=credentials").click();
});

This test searches for a DOM element with the ID #sidebar. Within this element, it looks for another element which matches the CSS selector a*=credentials. Finally, we simulate a click on this element (in this case a link to another view).

For a reference on CSS selectors, I would recommend having a look at this and this page.

You can simulate a click on a button <button>Store login credentials</button> whose text includes Store by using click and the *-selector. Use = to search for an exact match.

click('button*=Store')

For more complex selections, you can also chain elements. The next example searches for elements within the form which is of type input with the formcontrolName username.

element('form input[formControlName="username"]');

To check if the username field is initially empty and has focus, we execute this test:

it("test initial form", function () {
   return app.client
     .getText(usernameInput).should.eventually.equal('')
     .hasFocus(usernameInput);
}

Wrap Up

I hope that this article gave you a good first impression on how you to set up your own test environment for your Electron application with Spectron, Mocha, and Chai. You can find the full test class and a video showing the automated test in action on my website.

unit test Mocha (JavaScript framework) Electron (software framework) application

Published at DZone with permission of Dr. Matthias Sommer. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Introduction to Building Desktop Applications With Electron
  • Testing Serverless Functions
  • Microservices Testing: Key Strategies and Tools
  • How to Become a DevOps Engineer

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!