{"id":13515924,"url":"https://github.com/webpro/Automated-SPA-Testing","last_synced_at":"2025-03-31T05:31:06.300Z","repository":{"id":9274711,"uuid":"11105056","full_name":"webpro/Automated-SPA-Testing","owner":"webpro","description":"Automated unit \u0026 functional testing for web applications","archived":false,"fork":false,"pushed_at":"2017-06-15T22:20:59.000Z","size":12,"stargazers_count":105,"open_issues_count":0,"forks_count":12,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-18T14:46:20.070Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webpro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-07-01T19:43:46.000Z","updated_at":"2025-02-04T16:34:27.000Z","dependencies_parsed_at":"2022-09-10T11:11:23.507Z","dependency_job_id":null,"html_url":"https://github.com/webpro/Automated-SPA-Testing","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro%2FAutomated-SPA-Testing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro%2FAutomated-SPA-Testing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro%2FAutomated-SPA-Testing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro%2FAutomated-SPA-Testing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webpro","download_url":"https://codeload.github.com/webpro/Automated-SPA-Testing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246423527,"owners_count":20774795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T05:01:17.449Z","updated_at":"2025-03-31T05:31:05.811Z","avatar_url":"https://github.com/webpro.png","language":null,"readme":"**WARNING:** this repository and the information is outdated. The research was done in July of 2013. This repository is no longer maintained.\n\n# Automated SPA Testing\n\n## Introduction\n\nThis document represents some research done in order to find the best solution in client-side application testing, while meeting a set of requirements.\n\nMany of the things described are implemented in this [baseplate](https://github.com/webpro/baseplate) project.\n\nPlease feel free to comment e.g. by opening tickets, or comment on this README.\n\n## Contents\n\n* [Types of Testing](#types-of-testing)\n* [Requirements](#requirements)\n* [Test Frameworks](#test-frameworks)\n* [Assertion Libraries](#assertion-libraries)\n* [Test Doubles](#test-doubles)\n* [Test Runners](#test-runners)\n    * [BusterJS](#busterjs)\n    * [Intern](#intern)\n    * [Mocha](#mocha)\n    * [Karma](#karma)\n    * [Testem](#testem)\n    * [Functional Testing](#functional-testing)\n    * [Comparison Table](#comparison-table)\n    * [Performance](#performance)\n* [Functional Testing - Alternative Solutions](#functional-testing---alternative-solutions)\n* [CommonJS](#commonjs)\n\n## Types of Testing\n\nSome definitions of test type used here:\n\n* **Unit Testing**: validate correctness of isolated units of the application.\n* **Behavior Testing**: verify correct behavior of isolated functions based on user interaction, while faking events etc. in JavaScript.\n* **Functional Testing**: verify correct behavior of functions, while the browser itself is driven by the tests (think Selenium, WebDriver API).\n* **Integration Testing**: combine functions and involve real dependencies (CMS, database, etc.).\n* **Acceptance Testing**: validate correct behavior of the product by the customer.\n\nThis document focuses on unit and behavior testing for client-side single-page applications (SPA), leaving functional, integration and acceptance testing out of scope.\n\n## Requirements\n\n* Specs can be written in JavaScript\n* Support AMD setup (with RequireJS, maybe curl.js)\n* BDD style is preferred over TDD\n* Reuse tests across environments (e.g. browser, Node, PhantomJS)\n* Quickly run tests from CLI without a real browser (e.g. Node, PhantomJS)\n* Run the tests from CLI using real browsers installed on the system\n    * Run tests in multiple browsers in a single run\n    * Report back to CLI\n    * Bonus points: Automatically open \u0026 close browser\n* Include some and support extensible reporting formats (e.g. console, TAP)\n* Bonus points: Output code coverage information\n\n## Test Frameworks\n\nTest frameworks provide the interface to write tests, run the tests, and report results.\n\n* [Jasmine](https://jasmine.github.io/)\n* [Mocha](http://mochajs.org/)\n\nThese frameworks support BDD style tests.\n\n## Assertion Libraries\n\nAssertion libraries provide the interface to make \"assertions\" (in TDD). They're called \"expectations\" in BDD.\n\n* [chai](http://chaijs.com/)\n* [expect.js](https://github.com/LearnBoost/expect.js)\n\nMocha leaves this open, and Jasmine ships with Matchers (`expect()` style methods). All libraries can be extended with custom assertions/matchers.\n\nNote that Chai is a more popular choice and has more features, but does not support oldIE (while expect.js supports IE6+).\n\n## Test Doubles\n\nSince 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.\n\n* [Sinon.JS](http://sinonjs.org) is pretty much the de-facto standard here.\n* [Jasmine has Spies](https://jasmine.github.io/2.5/introduction#section-Spies) built-in, but can also be [paired](https://github.com/froots/jasmine-sinon) with Sinon.JS.\n\n## Test Runners\n\nTest runners drive the test frameworks. Currently, popular solutions include:\n\n* [BusterJS](http://busterjs.org)\n* [Intern](http://theintern.io)\n* [Karma](http://karma-runner.github.io)\n* [Mocha](http://mochajs.org/)\n* [Testem](https://github.com/airportyh/testem)\n\n### BusterJS\n\nBuster is a great effort and looks very interesting.\n\n#### Issues\n\nConfiguration 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`).\n\nFiled [issue #362](https://github.com/busterjs/buster/issues/362).\n\n#### Project Activity\n\nThe project has an explicit \"beta\" stamp on it. Project activity seems pretty low ([Community](http://docs.busterjs.org/en/latest/community/), [Twitter](https://twitter.com/buster_js), [Issue Tracker](https://github.com/busterjs/buster/issues)).\n\nOverall, this doesn't seem the right time to jump on this train (especially if things don't work straight away).\n\nOf course I would love to see [things](https://github.com/webpro/baseplate) working!\n\n### Intern\n\nIntern 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).\n\n### Karma\n\nKarma 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.\n\nKarma comes with a decent set of reporters, and custom reporters can be plugged in.\n\nFor code coverage, istanbul is included (they pair up great). This is [easy to configure](http://karma-runner.github.io/0.8/config/coverage.html) with various output formats (including `html`, `lcov`, and `cobertura`).\n\n### Mocha\n\nMocha is a test runner built with Node. It can run tests from CLI, but does not steer browsers.\n\nHowever, 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](https://github.com/mochajs/mocha/issues/770) since v1.10. However, things work using [mocha-phantomjs](http://metaskills.net/mocha-phantomjs/) and Mocha v1.9.\n\nMocha supports code coverage output out of the box. It can also be configured to work with:\n\n* [istanbul](https://github.com/yahoo/istanbul)\n* [Blanket.js](http://blanketjs.org)\n* [JSCoverage](http://siliconforks.com/jscoverage)\n\n### Testem\n\nTestem is built with Node (read more about it in [Testem: Interactive JS Test Runner](http://tobyho.com/2012/06/24/testem-interactive-js-test-runner/)).\n\nWhile configuration is not without hurdles in the other test runners, Testem has an advantage by the ability to hook into a [custom test page](https://github.com/airportyh/testem#custom-test-pages). 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`).\n\nIn short, if Jasmine or Mocha runs, Testem runs.\n\nAdditionally, a big plus of this strategy is that it's easy to configure functional testing (see below).\n\nA 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](https://github.com/richardbutler/testem-coverage-sandbox).\n\n### Behavior Testing\n\nBased 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:\n\n* Navigate the UI by clicking links or buttons, and display associated content.\n* Fill out a form and submit it by using the keyboard.\n* Simulate different ways  of interaction (i.e. mouse, keyboard, touch)\n\nThings 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:\n\n* Fixtures for initial DOM structures (to simulate e.g. pre-rendered HTML from CMS)\n* Ability to simulate user interaction such as clicks, key presses, etc.\n\nThere are a couple of caveats when programmatically simulating user interactions:\n\n* 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](https://github.com/mmonteleone/jquery.autotype) (untested).\n* Simulating touch events is possible by dispatching [Touch Events](http://www.w3.org/TR/touch-events/), or use something like [fake-touches](https://github.com/jtangelder/faketouches.js) (untested).\n\nIt'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](https://github.com/webpro/baseplate/blob/master/test/mocha-behavior/specs/moduleB.behavior.js) in a working example.\n\nIt should be feasible to do this with Karma as well (untested).\n\n### Comparison Table\n\nFeatures | BusterJS | Intern | Mocha (1) | Karma | Testem |\n:--|:-:|:-:|:-:|:-:|:-:\nAMD | Y ([2](http://docs.busterjs.org/en/latest/extensions/buster-amd/)) | Y | N ([3](http://metaskills.net/mocha-phantomjs)) | Y (2) | Y\nBDD | Y | Y | Y | Y | Y\nJasmine | N ([3](https://github.com/mattfysh/jasmine-buster)) | N | N (2) | Y (2) | Y\nMocha | N | N | Y | Y (2) | Y\nCLI: Node | Y | Y | N (4)\nCLI: PhantomJS | Y | Y ([2](https://github.com/theintern/intern/wiki/Using-Intern-with-PhantomJS)) | N ([3](http://metaskills.net/mocha-phantomjs)) | Y | Y\nCLI: Run tests in real browser | Y | Y | N | Y | Y\nCLI: Open/close browser | N | Y (5) | N | Y | Y\nCode coverage | | Y | | Y | N\nBehavior Tests | Y | N | | Y | Y\nFunctional Tests | N | Y | | N | N\n\n1. This is the Mocha test runner (Mocha client test framework is a feature)\n1. Feature included (e.g. as extension/adapter), but may require extra configuration.\n1. Feature available through external project.\n1. Mocha _uses_ Node, but not suited for AMD setup.\n1. Through Sauce Labs integration (not local).\n\n### Performance\n\nRunning 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:\n\nCommand | Time (real)\n:-- | ---\n`time testem ci -P 4` | 2.8s\n`time karma start --single-run` | 3.8s\n\nNot sure how things stack up on other systems, in other browsers and with more tests.\n\n## Functional Testing\n\nFor 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:\n\n* [CasperJS](http://casperjs.org/) - Functional testing solution on top of CasperJS (i.e. not in real browsers)\n* [Selenium WebDriver](http://docs.seleniumhq.org/projects/webdriver/) - API to automate testing web applications (available in [many languages](http://docs.seleniumhq.org/docs/03_webdriver.jsp), using [various browser drivers](https://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_Which_browsers_does_WebDriver_support?))\n* [WD.js](https://github.com/admc/wd) - WebDriver/Selenium 2 for Node ([used by Intern](https://github.com/theintern/intern#features))\n\nNote: The [WebDriver API](http://www.w3.org/TR/webdriver/) is a W3C standard (which in turn is based on Selenium WebDriver).\n\n## CommonJS\n\nSource 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.\n\nSwitching 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).\n\n## Conclusion\n\nPlease, draw your own! YMMV.\n","funding_links":[],"categories":["Technical"],"sub_categories":["ramanihiteshc@gmail.com"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebpro%2FAutomated-SPA-Testing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebpro%2FAutomated-SPA-Testing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebpro%2FAutomated-SPA-Testing/lists"}