I am having problems using any dojo modules with my functional test, I keep seeing window not defined errors or document not defined.
I am currently trying to use the dijit/registry like so (only importing its module so far)..
define([
'intern!object',
'intern/chai!assert',
'require',
'dijit/registry'
], function (registerSuite, assert, require, registry) {
registerSuite({
name: 'login',
'load and login': function () {
return this.remote.get(require.toUrl('http://application.co.uk/'))
.elementById('input1')
.click()
.type("username")
.end()
.elementById('input2')
.click()
.type("password")
.end()
.elementById('rememberMe')
.click()
.end()
.elementByName('Login.Submit')
.click()
.end()
.wait(5000)
.title()
.then(function (title) {
assert.strictEqual(title, 'Application title');
});
}
});
});
...and am getting the following error from node...
$ ./libs/intern/bin/intern-runner.js config=test/intern
Defaulting to "runner" reporter
Listening on 0.0.0.0:9000
c:/.../libs/dojo/_base/unload.js:6
var win = window;
^
ReferenceError: window is not defined
at c:/.../libs/dojo/_base/unload.js:6:11
at execModule (c:\...\libs\intern\node_modules\dojo\dojo.js:512:54)
at c:\...\libs\intern\node_modules\dojo\dojo.js:501:12
at Array.map (native)
at execModule (c:\...\libs\intern\node_modules\dojo\dojo.js:496:17)
at c:\...\libs\intern\node_modules\dojo\dojo.js:501:12
at Array.map (native)
at execModule (c:\...\libs\intern\node_modules\dojo\dojo.js:496:17)
at c:\...\libs\intern\node_modules\dojo\dojo.js:501:12
at Array.map (native)
I have read a previous question about using dojo/text! in a similar way which seemed to indicate the geezer version of Intern could handle this maybe?
The test runs fine without the registry module.
UPDATE
Ok so based on C Snover's response, you cant leverage anything like dijit/registry outside of a webdriver execute() method as the code needs to be within the context of the web browser not the functional test.
Functional tests run from within Node.js, not the browser environment. If you want to access the dijit/registry instance that was loaded in the page you are testing, you need to use execute to run a function within the remote environment:
return this.remote
.get('http://application.co.uk')
.execute(function () {
// this function runs in the browser!
var registry = require('dijit/registry');
// ... do things with registry
return something;
})
.then(function (something) {
// this function runs inside the test runner!
assert.isTrue(something);
});
You won’t be able to define dependencies that have DOM requirements (like dijit/registry) from functional test modules. Only browser-based unit test modules will be able to load such dependencies.
There's also the dijit-intern-helper -> https://github.com/SitePen/dijit-intern-helper
so this
executeAsync(function (done) {
require(['dijit/registry'], function (registry) {
done(registry.byId('titlePane').titleBarNode);
});
})
.then(function (node, setContext) {
setContext(node);
})
.click()
becomes
.then(dijit.nodeById('titlePane', 'titleBarNode'))
.click()
A blog post about it -> https://www.sitepen.com/blog/simplified-dijit-functional-testing/
Related
I'm writing tests for a JS application using Jasmine and testdouble.js as a mocking library. I am using AMD format to organize code in modules, and RequreJS as a module loader. I was wondering how to use testdouble.js to replace dependency for the module being tested that is in AMD format and it is loading via RequireJS. The documentation is unclear about this or I am missing something, so if someone could point me in the right direction.
I'll post the example bellow that illustrates my setup and the problem that I am facing.
car.js
define("car", ["engine"], function(engine) {
function drive = {
engine.run();
}
return {
drive: drive
}
});
engine.js
define("engine", function() {
function run() {
console.log("Engine running!");
}
return {
run: run
}
});
car.spec.js
define(["car"], function(car) {
describe("Car", function() {
it("should run the motor when driving", function() {
// I am not sure how to mock the engine's object run method
// and where to place that logic, in beforeEach or...
td.replace(engine, "run");
car.drive();
// How to verify that when car.run() has executed, it calls this mocked method
td.verify(engine.run());
});
});
});
testdouble.js does not have any explicit support for AMD modules. The only module-related tricks it offers are Node.js specific and built on top of Node's CJS module loader.
What you would need to do in this case is require from the test a reference to engine and replace the run property, which it seems like you've done (your example is incomplete).
If you do this, don't forget to run td.reset() in an afterEach to restore the original properties to anything you replace!
The code I'm trying to test relies on RequireJs loader plugins. Example with requirejs/text:
require(['text!templates/foo'], function (data) {
// handle loaded data
});
For a specific unit test, I'm trying to mock the response for text!templates/foo and override with one relevant for the test:
it('should load a template', function (done) {
// TODO: mock 'text!templates/foo' here to return 'mock_data'
// templateViewer uses the text plugin internally to do the actual loading
templateViewer.templateFor('foo', function (error, templateData) {
expect(templateData).toEqual('mock_data');
done();
});
});
I've looked at RequireJs dependency mock solutions, especially Squire.js but it seems they are all suited for mocking regular dependencies and not plugin responses.
I've also looked at stub libraries like sinon to maybe replace the actual require call but that seems problematic.
What's the recommended practice? I prefer not to replace the entire text plugin with a mock one in my requirejs configuration, just override some of its responses in specific tests.
My setup is node+mocha+requirejs
Edit
Please see this example fiddle project to see my issue with Squire:
http://runnable.com/VUBoI0ex6v9Gs-BJ/squirejs-with-plugins-for-node-js-and-hello-world
This will mock what you'd get from requiring text!foo/x.html. Plugins are not special, you just need to mock the entire path, including the plugin name.
var requirejs = require("requirejs");
var assert = require("assert");
requirejs.config({
baseUrl: __dirname,
packages: [
{
name: "squire",
location: "node_modules/squirejs",
main: "src/Squire"
}
]
});
var x;
before(function (done) {
requirejs(["squire"], function (Squire) {
var injector = new Squire();
injector.mock("text!foo/x.html", "foo").require(["text!foo/x.html"],
function (_x) {
x = _x;
done();
});
});
});
it("foo", function () {
assert.equal(x, "foo");
});
The problem you run into with the example code you added to your question is that you use the global require instead of using a require passed by your loader. You should add require as a dependency:
define(['require', ....], function (require, ....) {
The require module is special and reserved by RequireJS. It returns a reference to the require function. You must use it, for instance, when you use RequireJS's contexts so that a module loaded in a specific context uses a require function that is bound to that context. SquireJS also needs you to do this so that it can trap your calls to require. The global require bypasses SquireJS.
I have a simple mocha test that fails when using requirejs and the context config.
Here's A.js
define([], function(){
return {};
});
Here's the test spec.js
var requirejs = require('requirejs');
var localReq = requirejs.config({
baseUrl: "./",
context: "context1"
})
describe("context test", function () {
it("should not throw error", function () {
for (var i = 0; i < 100; i++) {
console.log(localReq("A"), i);
}
});
});
When I run the test mocha spec.js, I get the following error:
Uncaught Error: Tried loading "A" at /Users/khirakawa/work/test/node_modules/mocha/bin/A.js then tried node's require("A") and it failed with error: Error: Cannot find module 'A'
Here's a screenshot:
Notice how A was properly loaded and logged 100 times, yet the test still failed. If I comment out the context config, it works just fine.
Mocha is also printing out '1 passing' and '1 failing', even though there is only 1 test.
Why is this happening?
You could write your test like this:
describe("context test", function () {
it("should not throw error", function (done) {
localReq(["A"], function (f) { done(); });
});
});
As you pointed out in a comment, calling localReq to get a module synchronously should work but for some unexplained reason it does not. The code above, which calls localReq to load the module asynchronously, works.
The reason Mocha is saying that your single test is passing and failing is that it is detecting an error that happens after your test is over and has no other test to associate it with. This kind of error message where the same test both passes and fails is a sure indication that you've got something happening asynchronously but that you have not taken care of it in your Mocha test setup.
I am including Mocha.js with the excellent use shim for a Require.js-based site.
How do I access the define() and it() BDD functions declared by Mocha when using Require.js?
Here is a basic code example:
test.js:
var mocha = require('use!mocha')
, testFile = require('testFile.js')
mocha.setup('bdd');
mocha.run();
testFile.js:
define(function(require) {
// describe() and it() are not available
describe('Book', function() {
it('should have pages', function() {
});
});
});
I get the error Uncaught ReferenceError: describe is not defined when running in the browser.
I have tried window.describe and tried moving the require('testFile.js') to after the mocha.setup('bdd'). I know I am missing something. Probably passing the context to mocha somehow.
The problem is that the global functions such as describe and it are set up by mocha.setup(). You can use shim config's init property to call mocha.setup() before mocha is exported.
requirejs.config({
shim: {
'mocha': {
init: function () {
this.mocha.setup('bdd');
return this.mocha;
}
}
}
});
require(['mocha', 'test/some_test'], function (mocha) {
mocha.run();
});
Test files need to require mocha.
define(['mocha'], function (mocha) {
describe('Something', function () {
// ...
});
});
Shim config's init property was introduced in RequireJS 2.1. You might be able to use exports property instead of init with RequireJS 2.0.
I found the solution in geddski's amd-testing examples project.
Instead of including the test file(s) at the top along with mocha like so:
define(['use!mocha', 'testFile'],
function(Mocha, TestFile) {
mocha.setup('bdd');
mocha.run();
});
The test file(s) should be included as another require call and mocha.run() embedded in the callback:
define(['use!mocha'],
function(Mocha) {
mocha.setup('bdd');
// Include the test files here and call mocha.run() after.
require(['testFile'],
function(TestFile) {
mocha.run();
});
});
I'm just getting started with require.js. I have successfully wrapped jquery, some plugins, and a couple of my own modules. I'm trying to interact with my modules (or jquery) from Firebug (or Google Chrome's JS console), and I'm not having much luck.
What is the correct way to access these modules from the console?
Say we have module /app/scripts/methodsModule.js that returns a few methods:
define({
someMethod: function() {
// do stuff
},
anotherMethod: function() {
// do some more stuff
}
});
In our data-main file /app/scripts/main.js we have:
require(['methodsModule'], function(methods) {
methods.someMethod() // call someMethod
methods.anotherMethod() // call anotherMethod
})
Once requireJS loads up our data-main, we can access any modules that have already been loaded by requireJS from the javascript console command line like so:
>> methods = require('methodsModule'); // requireJS has module methodsModule stored
>> methods.someMethod() // call someMethod
>> methods.anotherMethod() // call anotherMethod
If a module hasn't been loaded by a call to require() or define(), we have to pass our own callback for the require function to call after the module has been loaded:
>> myCB = function(methods) { methods.someMethod() }
>> require(['methodsModule'], myCB)
Otherwise, requireJS throws an error saying that the module has not yet been loaded..
There is a way without using callbacks.
If you module was not required in console or you application before, you can just require it first:
require(['methodsModule']);
after that you can use "dynamic" require to access it:
require('methodsModule').someMethod();