• Stars
    star
    105
  • Rank 328,196 (Top 7 %)
  • Language
  • Created over 11 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Automated unit & functional testing for web applications

WARNING: this repository and the information is outdated. The research was done in July of 2013. This repository is no longer maintained.

Automated SPA Testing

Introduction

This document represents some research done in order to find the best solution in client-side application testing, while meeting a set of requirements.

Many of the things described are implemented in this baseplate project.

Please feel free to comment e.g. by opening tickets, or comment on this README.

Contents

Types of Testing

Some definitions of test type used here:

  • Unit Testing: validate correctness of isolated units of the application.
  • Behavior Testing: verify correct behavior of isolated functions based on user interaction, while faking events etc. in JavaScript.
  • Functional Testing: verify correct behavior of functions, while the browser itself is driven by the tests (think Selenium, WebDriver API).
  • Integration Testing: combine functions and involve real dependencies (CMS, database, etc.).
  • Acceptance Testing: validate correct behavior of the product by the customer.

This document focuses on unit and behavior testing for client-side single-page applications (SPA), leaving functional, integration and acceptance testing out of scope.

Requirements

  • Specs can be written in JavaScript
  • Support AMD setup (with RequireJS, maybe curl.js)
  • BDD style is preferred over TDD
  • Reuse tests across environments (e.g. browser, Node, PhantomJS)
  • Quickly run tests from CLI without a real browser (e.g. Node, PhantomJS)
  • Run the tests from CLI using real browsers installed on the system
    • Run tests in multiple browsers in a single run
    • Report back to CLI
    • Bonus points: Automatically open & close browser
  • Include some and support extensible reporting formats (e.g. console, TAP)
  • Bonus points: Output code coverage information

Test Frameworks

Test frameworks provide the interface to write tests, run the tests, and report results.

These frameworks support BDD style tests.

Assertion Libraries

Assertion libraries provide the interface to make "assertions" (in TDD). They're called "expectations" in BDD.

Mocha leaves this open, and Jasmine ships with Matchers (expect() style methods). All libraries can be extended with custom assertions/matchers.

Note that Chai is a more popular choice and has more features, but does not support oldIE (while expect.js supports IE6+).

Test Doubles

Since unit testing means testing isolated and dependency-free units, dependencies need to be mocked or stubbed out (i.e. "test doubles"). For instance, method calls to modules the unit depends on, and XHR calls to services.

Test Runners

Test runners drive the test frameworks. Currently, popular solutions include:

BusterJS

Buster is a great effort and looks very interesting.

Issues

Configuration requires to load all files that might be needed. E.g. sources: ["src/**/*.js", "lib/**/*.js"]. This might include a lot of unnecessary files (libraries may come with a large number of files that are not needed to use it), so it's not great performance wise. But the actual issue is that some matching .js files are Node executables, and thus start with a hash-bang (i.e. #!/usr/bin/env node), causing a fatal error for Buster ([Fatal] Syntax error).

Filed issue #362.

Project Activity

The project has an explicit "beta" stamp on it. Project activity seems pretty low (Community, Twitter, Issue Tracker).

Overall, this doesn't seem the right time to jump on this train (especially if things don't work straight away).

Of course I would love to see things working!

Intern

Intern is the new kid on the block, and it's quite impressive and complete. Many features come out of the box or are in the works, including Sauce Labs and Travis CI integration, functional testing (WebDriver API), and various code coverage reporters (istanbul).

Karma

Karma is a testacular effort from the AngularJS team, powered by Node and Socket.IO. It is fairly easy to set up. Configuration may result in some headaches for AMD setups (you want to reuse existing application and test configuration files). However, once it's done it doesn't need to be looked after anymore.

Karma comes with a decent set of reporters, and custom reporters can be plugged in.

For code coverage, istanbul is included (they pair up great). This is easy to configure with various output formats (including html, lcov, and cobertura).

Mocha

Mocha is a test runner built with Node. It can run tests from CLI, but does not steer browsers.

However, it could still complement a setup where Mocha is the client test framework, and the test runner doesn't support running tests in Node. It could be complementary, if the Mocha test runner would support AMD. And this could be solved by using PhantomJS, if Mocha didn't have this issue since v1.10. However, things work using mocha-phantomjs and Mocha v1.9.

Mocha supports code coverage output out of the box. It can also be configured to work with:

Testem

Testem is built with Node (read more about it in Testem: Interactive JS Test Runner).

While configuration is not without hurdles in the other test runners, Testem has an advantage by the ability to hook into a custom test page. When a page is configured for testing (i.e. with Jasmine or Mocha), that page needs two extra lines of code (to inject testem.js). Then, if Testem is driving the show, it automatically detects the framework in the page, and hooks into it (i.e. with a custom reporter for Jasmine, or monkey-patching Mocha's Runner.prototype.emit).

In short, if Jasmine or Mocha runs, Testem runs.

Additionally, a big plus of this strategy is that it's easy to configure functional testing (see below).

A downside of Testem is that it doesn't have support for code coverage (at least not built-in). Since Testem hooks into the client side frameworks, those can be configured to use coverage reporters (but after generating coverage files from sources). One working effort includes Testem Coverage Sandbox.

Behavior Testing

Based on the given definition ("verify correct behavior of isolated functions based on user interaction, while faking events etc. in JavaScript"), the challenge is to initialize a function of the application, and then simulate user interaction with it. Examples include:

  • Navigate the UI by clicking links or buttons, and display associated content.
  • Fill out a form and submit it by using the keyboard.
  • Simulate different ways of interaction (i.e. mouse, keyboard, touch)

Things are actually quite feasible, even simple, when extending the workflow and tools for unit testing to functional tests. What is needed on top of this:

  • Fixtures for initial DOM structures (to simulate e.g. pre-rendered HTML from CMS)
  • Ability to simulate user interaction such as clicks, key presses, etc.

There are a couple of caveats when programmatically simulating user interactions:

  • Filling out an input field (e.g. $('input[name=firstName]').val('John')) won't trigger a "change" event. This can be simulated by appending .trigger('change'), or use something like jQuery.autotype (untested).
  • Simulating touch events is possible by dispatching Touch Events, or use something like fake-touches (untested).

It's actually trivial to set this up using Testem, Jasmine (or Mocha) and jQuery. Driven by Testem, the functional tests can easily be ran cross-browser and/or quickly using only PhantomJS. Here is how it might look like in a working example.

It should be feasible to do this with Karma as well (untested).

Comparison Table

Features BusterJS Intern Mocha (1) Karma Testem
AMD Y (2) Y N (3) Y (2) Y
BDD Y Y Y Y Y
Jasmine N (3) N N (2) Y (2) Y
Mocha N N Y Y (2) Y
CLI: Node Y Y N (4)
CLI: PhantomJS Y Y (2) N (3) Y Y
CLI: Run tests in real browser Y Y N Y Y
CLI: Open/close browser N Y (5) N Y Y
Code coverage Y Y N
Behavior Tests Y N Y Y
Functional Tests N Y N N
  1. This is the Mocha test runner (Mocha client test framework is a feature)
  2. Feature included (e.g. as extension/adapter), but may require extra configuration.
  3. Feature available through external project.
  4. Mocha uses Node, but not suited for AMD setup.
  5. Through Sauce Labs integration (not local).

Performance

Running a single test, including opening and closing 4 different browsers is fast in Karma and Testem. Testem has the option to run browsers in parallel, while Karma seems to do this automatically. The (same) test is run using minimal, default settings; Jasmine; and in Chrome, Chrome Canary, Firefox and PhantomJS:

Command Time (real)
time testem ci -P 4 2.8s
time karma start --single-run 3.8s

Not sure how things stack up on other systems, in other browsers and with more tests.

Functional Testing

For functional testing, when the browser itself needs to be driven by the tests (e.g. for page navigation, file uploads), solutions like the following might be interesting to check out:

Note: The WebDriver API is a W3C standard (which in turn is based on Selenium WebDriver).

CommonJS

Source code can be written in CommonJS, and be wrapped in the AMD transporter format for the browser. In doing so, some things around testing would probably get easier. Especially configuration and running stuff in Node (think Mocha) come to mind. The Mocha test runner drives CommonJS-style modules/specs. Interesting if real browser testing is out of scope, and e.g. speed and code coverage reporting options are more important.

Switching to CommonJS source and spec files doesn't seem of much benefit to Karma and Testem (apart from ease of configuration). Both Karma and Testem can pre-process source files if needed (i.e. convert to AMD).

Conclusion

Please, draw your own! YMMV.

More Repositories

1

awesome-dotfiles

A curated list of dotfiles resources.
8,206
star
2

reveal-md

reveal.js on steroids! Get beautiful reveal.js presentations from any Markdown file
JavaScript
3,365
star
3

programming-principles

Categorized overview of programming principles & design patterns
2,424
star
4

knip

βœ‚οΈ Find unused files, dependencies and exports in your JavaScript and TypeScript projects. Knip it before you ship it!
TypeScript
1,842
star
5

dotfiles

Dotfiles for macOS
Shell
983
star
6

dyson

Node server for dynamic, fake JSON.
JavaScript
832
star
7

DOMtastic

Small, fast, and modular DOM and event library for modern browsers.
JavaScript
763
star
8

awesome-newsletters

The best (weekly) newsletters
379
star
9

component-styleguide

Simple styleguide framework
JavaScript
122
star
10

responsive-web-apps

Building Responsive Web Applications
JavaScript
63
star
11

grunt-release-it

Interactive release task for Git repositories. Optionally release a build to distribution/component repository.
JavaScript
48
star
12

versionify

Browserify transform to replace placeholder with package version
JavaScript
33
star
13

react-redux-demo

Fun Fair
JavaScript
30
star
14

baseplate

The baseplate project provides excellent workflow & tooling to develop, build, and test non-trivial SPAs.
JavaScript
24
star
15

bron

πŸƒβ€β™‚οΈ Fast & tiny test runner for Node.js
JavaScript
18
star
16

frameground

Compare JavaScript Frameworks. Please share your knowledge!
JavaScript
17
star
17

dyson-generators

Fake data generators, used by dyson and dyson-image
JavaScript
17
star
18

dyson-demo

Demo package for dyson
JavaScript
14
star
19

requirejs-handlebars

Simple Handlebars plugin for RequireJS
JavaScript
13
star
20

precompiled-templates

Performance, footprint and configuration of template engines and precompiled templates
JavaScript
12
star
21

ts-morph-helpers

Helpers for ts-morph
TypeScript
12
star
22

component-styleguide-example

Example for component-styleguide
CSS
9
star
23

DuckJS

Tiny and powerful module loader to lazy load HTML+CSS+JS
JavaScript
8
star
24

benchrunner

Benchmark Suite Runner for benchmark.js
JavaScript
8
star
25

sandbox

Source files for sandbox.webpro.nl (offline)
JavaScript
6
star
26

dyson-image

JavaScript
6
star
27

webpro.nl

Source code of webpro.nl
Astro
6
star
28

doxstrap

Yet another documentation generator
HTML
5
star
29

vars

Common patterns in Vue, Angular, React and Svelte
JavaScript
5
star
30

parse-openapi

OpenAPI v3 parser
TypeScript
5
star
31

nx-tsc

Nx executor to type-check project source files using `tsc --noEmit`
JavaScript
5
star
32

hyte

HYbrid TEmplating for the browser and Node
JavaScript
4
star
33

Websites-vs-Web-Applications

Responsive Adaptive Rainwebs FTW!
4
star
34

release-it-monorepo

4
star
35

github-pages-example

GitHub Pages Example
3
star
36

bookstore

Simple application to learn GraphQL and Next.js.
JavaScript
3
star
37

markdown-rambler

Yet another opinionated & powerful static site generator.
TypeScript
3
star
38

bump-file

Bump JSON files (e.g. package.json and friends)
JavaScript
3
star
39

openapi-parser

OpenAPI v3 parser
TypeScript
2
star
40

fix-sourcemaps

Fix sources and file in sourcemaps
JavaScript
2
star
41

jaguarundi

Ant build script to optimize and version Javascript, CSS, and HTML files
JavaScript
2
star
42

requirejs-hogan

Simple Hogan plugin for RequireJS
JavaScript
2
star
43

requirejs-dust

Simple Dust plugin for RequireJS
JavaScript
2
star
44

deprecated-obj

Compares deprecations against a configuration object, and returns a compliant object and violations
JavaScript
2
star
45

DOMtastic-release

JavaScript
1
star
46

is-subdir

Check if a directory is a subdirectory
JavaScript
1
star
47

SpringbokJS

Installs modules (traditional object or AMD-style) based on HTML attributes.
JavaScript
1
star
48

last-publish

Get the date of the last published version of a package in the npm registry
JavaScript
1
star