How to Write Unit Tests for Kanso - unit-testing

I've written a lot of django applications and become accustomed to extending unittest.TestCase and running python manage.py test app_name. Is there a similarly simple way to unit test Kanso apps? Please provide a minimal example.
Thanks.

Kanso apps are CouchDB apps. However the best bang-for-buck is to ignore CouchDB for now. The important thing is this: Kanso apps are Node.js apps. Test them the same way you would test a Node.js app. Test that they adhere to the documented CouchDB API and you will be fine.
Ideally, we might want to run tests actually in CouchDB. The JavaScript engines are different (V8 vs. SpiderMonkey); the environments are different. However in practice, it is so much easier to test Node.js code. (Also, a whole class of JavaScript bugs are absent on both platforms: third-party code setting global variables, changing built-in types, changing prototypes—those are all browser issues. Node.js and CouchDB are both pristine and predictable.)
Example
Let's make a simple Couch app that outputs "Hello world" in a _show function.
The kanso.json file:
{ "name" : "hello_world"
, "version": "0.1.0"
, "description": "A simple hello-world Couch app"
, "dependencies": { "node-couchapp": "~0.8.3" }
, "app": "app"
}
Next run kanso install which will pull in the "node-couchapp" dependency. (Notice how using the kanso command is similar to using the npm command.)
Let's make a very simple Couch app, in ./app.js:
// A Couch app that just says hello in a _show function.
module.exports = {
'shows': {
'hello': function(doc, req) {
var who = req.query.who || "world"
return "Hello, " + who
}
}
}
I ran kanso push http://example.iriscouch.com/so_hello and I can see my app here:
http://example.iriscouch.com/so_hello/_design/hello_world/_show/hello
http://example.iriscouch.com/so_hello/_design/hello_world/_show/hello?who=Stack+Overflow
Adding Tests
I like node-tap so let's use that. But the main point is, this is just some Node.js code. Test it using whatever method your prefer.
First, a quick package.json file:
{ "name" : "hello_world"
, "description": "A simple hello-world Couch app"
, "version": "0.1.0"
, "private": true
, "devDependencies": { "tap": "~0.2.3" }
}
Run npm install to get the node-tap package. (And I always have ./node_modules/.bin in my $PATH when I work on Node.js. Rather than a global install, I like to have everything I need right there in the project.
Next, perhaps a test/show_function.js file:
var tap = require('tap')
tap.test('The Couch app loads', function(t) {
t.doesNotThrow(load_app, 'No problem loading the app.js file')
t.end()
function load_app() {
var app = require('../app')
}
})
tap.test('The show function', function(t) {
var app = require('../app')
, hello = app.shows.hello
t.type(hello, 'function', 'Show function "hello" in the couch app')
var doc = {}
, null_req = {'query':{}}
, john_req = {'query':{'who':'John Doe'}}
t.equal(hello(doc, null_req), 'Hello, world', '"Hello world" by default')
t.equal(hello(doc, john_req), 'Hello, John Doe', 'Supports ?who query string')
t.end()
})
Test it by running tap test:
$ tap test
ok test/show_function.js ................................ 5/5
total ................................................... 5/5
ok
I'll change the code to return "Hello, world" hard-coded (i.e., ignore the req.query.who parameter). Notice the failing test:
$ tap test
not ok test/show_function.js ............................ 4/5
Command: "node" "show_function.js"
ok 1 No problem loading the app.js file
ok 2 Show function "hello" in the couch app
ok 3 "Hello world" by default
not ok 4 Supports ?who query string
---
file: /private/tmp/j/test/show_function.js
line: 23
column: 5
stack:
- getCaller (/private/tmp/j/node_modules/tap/lib/tap-assert.js:403:17)
- assert (/private/tmp/j/node_modules/tap/lib/tap-assert.js:19:16)
- Function.equal (/private/tmp/j/node_modules/tap/lib/tap-assert.js:160:10)
- Test._testAssert [as equal] (/private/tmp/j/node_modules/tap/lib/tap-test.js:86:16)
- Test.<anonymous> (/private/tmp/j/test/show_function.js:23:5)
- Test.<anonymous> (native)
- Test.<anonymous> (events.js:88:20)
- Test.emit (/private/tmp/j/node_modules/tap/lib/tap-test.js:103:8)
- GlobalHarness.<anonymous> (/private/tmp/j/node_modules/tap/lib/tap-harness.js:86:13)
- Array.0 (native)
found: Hello, world
wanted: Hello, John Doe
diff: |
FOUND: Hello, world
WANTED: Hello, John Doe
^ (at position = 7)
...
ok 5 test/show_function.js
1..5
# tests 5
# pass 4
# fail 1
total ................................................... 4/5
not ok

I have some projects that may help showcase testing kanso apps:
Dashboard Core Project
https://github.com/ryanramage/dashboard-core
Features:
Travis Support.
PhantomJS headless testing using NodeUnit
Since this is a module, we have a test folder, that is a seperate kanso app that uses the module. Note in the packages folder there is a symlink back to the root of the project.
Node-Couchapp Project
https://github.com/kanso/node-couchapp
Travis support
This time multiple test kanso projects in the kanso folder. Again using the symlink trick in the package directory

Like JasonSmith, I also recommend you test using Node.js where possible. However, due to the nature of CouchApps you often end up having to write unit tests to run in the browser, either because they interact with browser APIs you don't want to mock or because you need to test it works in a range of browsers.
When doing browser-based unit tests I use a few little Kanso packages I hacked together to automatically present an interface for running nodeunit test suites. It's a bit rough around the edges at the moment but gets the job done.
kanso.json
Add nodeunit and nodeunit-testrunner packages to your kanso.json file and run kanso install to fetch them from the repositories.
{
"name": "example",
"version": "0.0.1",
"description": "example app with unit tests",
"modules": ["lib", "tests"],
"load": "lib/app",
"dependencies": {
"modules": null,
"properties": null,
"nodeunit": null,
"nodeunit-testrunner": null
}
}
Notice that I've included the 'tests' directory as a module path. Any modules dropped into that directory will be used as nodeunit test suites and displayed by the nodeunit-testrunner UI.
Rewrites
You need to manually add the nodeunit-testrunner package's rewrites to your app, in my example that means editing lib/app.js to look like the following:
exports.rewrites = [
require('nodeunit-testrunner/rewrites')
];
Add some tests
Assuming we have a module lib/foo.js that looks like this:
exports.hello = function (name) {
return 'hello ' + name;
};
We could add a test by adding a module at tests/test-foo.js (this can be named anything so long as it's inside the tests directory).
var foo = require('lib/foo');
exports['test for foo.hello'] = function (test) {
test.equal(foo.hello('bar'), 'hello bar');
test.done();
};
If you then push your app and visit http://localhost:5984/example/_design/example/_rewrite/test in the browser you will be presented with a basic interface for running the test suites in the tests directory, either individually or all of them one after another.
Hope that helps.

Related

How to specify test tags correctly in dart_test.yaml?

I have a dart project that has several tests, when I try to run an isolated test I get this warning:
Warning: A tag was used that wasn't specified in dart_test.yaml.
"tagName" was used in the suite itself
how should i declare these tags correctly in dart_test.yaml?
Steps
Create a file dart_test.yaml at the root of your project
Add your tags one after another under a tags field
Add tags to your test or testWidget declaration
Run your tests with the -t flag followed by the wanted tag
Sample
Let's say I want to add the following tags: golden, atom, molecule, organism, mobile, desktop. My dart_test.yaml will look like this:
tags:
golden:
atom:
molecule:
organism:
mobile:
desktop:
And everything should be okay you can write your test:
void main() {
testWidgets(
'this is a test',
(tester) async {
// ...
},
tags: ['atom', 'mobile'],
);
}
You can run it with the following command:
$ flutter test -t mobile
source

How to mock global Vue.js variable in JEST test

I have a global property/variable with my app urls:
Vue.prototype.$apiUrls = {
root: 'http://localhost:8080/',
api: 'api/v1/'
// etc.
}
I use it inside my components as axios request:
axios.get(`${this.$apiUrls.root}${this.$apiUrls.api}/users/`)
Now I want to test my component's code, I've mocked axios already, but still I receive an error:
TypeError: Cannot read property '$apiUrls' of undefined
I've tried to define/mock this property inside each test and/or in JEST's setup file, like e.g.
global.$apiUrls = {...}
// or
Vue.prototype.$apiUrls = {...}
// or
Object.defineProperties(Vue.prototype, {$apiUrls: {...}})
I've also tried mocking it to window or this (yeah, thats silly), but with no success - I still receive that error - please help.
There is two ways to achieve this. One is using the Config option, as mentioned by #Aldarund. You can read about it here.
If you are using Jest, I recommend doing this in the jest.init.js file:
import { config } from '#vue/test-utils'
config.mocks['$apiUrls'] = {
'some/endpoint'
}
Then add this to the jest section of your package.json:
"setupFiles": [
"<rootDir>/jest.init.js"
]
Now it is globally mocked. If you want to do this on a per test basis, you can use the mocks mounting option:
const wrapper = shallowMount(Foo, {
mocks: {
$apiUrls: 'some/endpoint'
}
})
Hopefully this helps!
If you are interested I am compiling a collection of simple guides on how to test Vue components here. It's under development, but feel free to ask make an issue if you need help with other related things to testing Vue components.
I don't think the answers above work anymore (in 2020).
Here's what worked for me:
For vue-test-utils 1.x.x (Vue 2)
Create a new file, name it eg. jest.init.js
Give it the following content:
import { config } from "#vue/test-utils";
config.mocks["yourGlobalProperty"] = label => label; //you can replace it with your own mock
Add this to your jest.config.js (actually write "rootDir", don't replace anything with a real path)
module.exports = {
setupFiles: ["<rootDir>/jest.init.js"]
}
These files will be only ran before jest runs unit tests.
Note that I'm importing {config}, not the default export. I don't know why the default didn't work for me. Even the documentation for vue test utils doesn't import the default export anymore
Also make sure you're not trying to import from the old vue-test-utils package. (The new one is #vue/test-utils)
For #vue/test-utils 2.x.x (vue-test-utils-next) (Vue 3)
Follow steps like for 1.x.x above, but in step two, do this instead:
import { config } from "#vue/test-utils"; //2.0.0-beta.5
config.global.mocks = {
yourGlobalProperty: label => label
};
You can do it with vue-test-utils beta 15 and later.
Here docs
And some example would be:
import VueTestUtils from '#vue/test-utils'
VueTestUtils.config.mocks['$apiUrls'] = {
...
}

Jest globalSetup option not working

I'm trying to make a function called loadFixtures available to all Jest tests.
I have the following line within the jest config object inside package.json:
"globalSetup": "<rootDir>/src/test/js/config/setup-globals.js"
setup-globals.js contains:
module.exports = function() {
function loadFixtures(filename) {
console.info('loadFixtures is working');
}
}
Within my tests I have, for example:
beforeEach(() => {
loadFixtures('tooltip-fixture.html');
});
However when I run Jest I get the following for each test:
ReferenceError: loadFixtures is not defined
I verified that the setup-globals.js file is definitely being found and loaded in by Jest before the tests execute.
Can anyone assist in identifying where I've gone wrong here? I've spent pretty much an entire day trying to debug without luck.
You should be using setupFiles and not globalSetup.
// jest config
"setupFiles": [
"<rootDir>/src/test/js/config/setup-globals.js"
]
then src/test/js/config/setup-globals.js:
global.loadFixtures(filename) {
console.info('loadFixtures is working');
}
references: https://medium.com/#justintulk/how-to-mock-an-external-library-in-jest-140ac7b210c2
If you bootstrapped your application using npx create-react-app (CRA), you do not need to add the setupFiles key under your jest key in the package.json file (CRA prevents overriding that key).
what you simply need to do is to add the file setupTests.js in the root of your SRC folder, and populate it with the snippet below:
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({
adapter: new Adapter(),
});
remember you must have earlier installed the right versions of enzyme and enzyme-adapter-react
CRA has been wired to automatically load the setupTests.js file in the src folder if it exists. Hence after adding these, you can then go over to your test and do import {shallow} from enzyme without triggering an error.
if you are not using Create-react-app, all you need to do, in addition to adding the file above to your src folder is to add the key setupFiles into the jest key in your package.json. it should look like this:
"jest": {
"setupFiles": ['<rootDir>/src/setupTests.js'],
}
and you are good to go.
Cheers!
You're defining a function in a different scope. How about you create a separate module and import it directly in your test files. Or if you really want to define it in the global scope, try using the following code in your setup-globals.js file.
module.exports = function() {
global.loadFixtures = function(filename) {
console.info('loadFixtures is working');
}
}

Testing service in Angular returns module is not defined

I am trying to run the default service unit test in my project (Taken from the Angular Seed project on GitHub), but I keep getting the error "module is not defined".
I have read that it could be something to do with the order of the referenced JavaScript files, but I can't seem to get it to work, so hopefully one of you might be able to help.
My configuration for the test looks like this:
basePath = '../';
files = [
'public/javascripts/lib/jquery-1.8.2.js',
'public/javascripts/lib/angular.js',
'public/javascripts/lib/angular-.js',
'public/app.js',
'public/controllers/.js',
'public/directives.js',
'public/filters.js',
'public/services.js',
JASMINE,
JASMINE_ADAPTER,
'public/javascripts/lib/angular-mocks.js',
'test/unit/*.js' ];
autoWatch = true;
browsers = ['Chrome'];
junitReporter = { outputFile: 'test_out/unit.xml', suite: 'unit'
};
The service looks like the following:
angular.module('myApp.services', []).
value('version', '0.1');
The test looks like this:
'use strict';
describe('service', function() {
beforeEach(module('myApp.services'));
describe('version', function() {
it('should return current version', inject(function(version) {
expect(version).toEqual('0.1');
}));
});
});
And the error when running the test through testacular is this:
ReferenceError: module is not defined
You are missing the angular-mocks.js file.
I had the same problem, and I understood why it wasn't working:
The jasmine.js javascript must be referenced BEFORE the angular-mocks.js file.
Indeed, the angular-mocks.js checks if Jasmine is loaded, and only if it is it will add the module function to the window.
Here is an extract of Angular Mocks code:
(Edit after the few comments about 'hacking' I had below: this is just an extract of the code, this is not something you need to write yourself, it's already there!)
window.jasmine && (function(window) {
[...]
window.module = angular.mock.module = function() {
var moduleFns = Array.prototype.slice.call(arguments, 0);
return isSpecRunning() ? workFn() : workFn;
/////////////////////
[...]
};
In a nutshell:
Just reference your jasmine.js before angular-mocks.js and off you go.
The window.module function comes in angular-mocks.js and is a shorthand for angular.mock.module. As mentioned in the docs, the module function only works with Jasmine.
Using Testacular, the following example configuration file will load angular-mocks.js.
/** example testacular.conf.js */
basePath = '../';
files = [
JASMINE,
JASMINE_ADAPTER,
'path/to/angular.js',
'path/to/angular-mocks.js', // for angular.mock.module and inject.
'src/js/**/*.js', // application sources
'test/unit/**/*.spec.js' // specs
];
autoWatch = true;
browsers = ['Chrome'];
And, as suggested elsewhere, you can run Testacular with debug logging to see what scripts are loaded (you can also see the same in the inspector):
testacular --log-level debug start config/testacular.conf.js
The angular.mock.inject docs include a pretty complete example.
We use 'module' without 'angular' in our unit tests and it works fine.
CoffeeScript:
describe 'DiscussionServicesSpec', ->
beforeEach module 'DiscussionServices'
beforeEach inject ... etc.
which compiles to
JavaScript:
describe('DiscussionServices', function() {
beforeEach(module('DiscussionServices'));
beforeEach(inject(function ... etc.
The only time I see something like the error you described is if in the testacular.conf.js file the angular-mocks.js file is not listed in the files section before the specs trying to use 'module'. If I put it after my tests in the 'files' list I get
ReferenceError: Can't find variable: module
(Our tests are being run through PhantomJS)
I had included angular-mocks.js in my karma config, but was still getting the error. It turns out the order is important in the files array. (duh) Just like in the head of an html doc, if a script calls angular before it's defined, and error occurs. So I just had to include my app.js after angular.js and angular-mocks.js.
If you're using Yeoman and its angular-generator, you probably get this error. Especially when you do the Tutorial ( ._.)
I fixed it, by copying the angular-mocks.js file, from the bower_components/angular-mocks dir to the test/mock dir. Of course you have to be sure, that your karma.conf.js file is configured correctly.
Greetings!
I had this same issue when I was doing something like var module = angular.module('my',[]). I needed to make sure it was surrounded by IIFE

using mocha testing with cloud9, execute mocha tests from node.js

I was wondering if there is a way to execute mocha tests programmatically from node.js so that I can integrate unit tests with Cloud 9. The cloud 9 IDE has a nice feature where whenever a javascript files is saved, it looks for a file with the same name, ending with either "_test" or "Test" and runs it automatically using node.js. For example it has this code snippet in a file demo_test.js which automatically runs.
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
Is there something like this I could use to run a mocha test? Something like a mocha(this).run()?
The essentials to programmatically run mocha:
Require mocha:
var Mocha = require('./'); //The root mocha path (wherever you git cloned
//or if you used npm in node_modules/mocha)
Instatiate call the constructor:
var mocha = new Mocha();
Add test files:
mocha.addFile('test/exampleTest'); // direct mocha to exampleTest.js
Run it!:
mocha.run();
Add chained functions to programmatically deal with passed and failed tests. In this case add a call back to print the results:
var Mocha = require('./'); //The root mocha path
var mocha = new Mocha();
var passed = [];
var failed = [];
mocha.addFile('test/exampleTest'); // direct mocha to exampleTest.js
mocha.run(function(){
console.log(passed.length + ' Tests Passed');
passed.forEach(function(testName){
console.log('Passed:', testName);
});
console.log("\n"+failed.length + ' Tests Failed');
failed.forEach(function(testName){
console.log('Failed:', testName);
});
}).on('fail', function(test){
failed.push(test.title);
}).on('pass', function(test){
passed.push(test.title);
});
Your mileage may vary, but I concocted the following one-liner a while back and it has served me pretty well:
if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
Additionally, if you want it to be output in asyncjs format that Cloud9 is expecting, you'll need to provide a special reporter. Here's a really simple example of what a simple reporter would look like:
if (!module.parent){
(new(require("mocha"))()).ui("exports").reporter(function(r){
var i = 1, n = r.grepTotal(r.suite);
r.on("fail", function(t){ console.log("\x1b[31m[%d/%d] %s FAIL\x1b[0m", i++, n, t.fullTitle()); });
r.on("pass", function(t){ console.log("\x1b[32m[%d/%d] %s OK\x1b[0m", i++, n, t.fullTitle()); });
r.on("pending", function(t){ console.log("\x1b[33m[%d/%d] %s SKIP\x1b[0m", i++, n, t.fullTitle()); });
}).addFile(__filename).run(process.exit);
}