This question already has an answer here:
Chai should is undefined
(1 answer)
Closed 5 years ago.
Context
I'm a JavaScript hobbyist, and to take my project to the next level, I'm trying to setup a pipeline in BitBucket that will run my unit tests (and do other things later on).
I already used Mocha and Chai for testing, but I used it in the browser using an html page that sets up the dependencies and runs the tests.
Problem
The problem I'm facing is that I can't get the should syntax to work in node, while I did have working tests before in the browser. should should be available as part of the Chai library.
I initialized a new project with minimal code in it, but here it also doesn't work: should simply is not assigned.
package.json, including mocha and chai, and setting up mocha for testing.
{
"name": "testtest",
"version": "1.0.0",
"description": "Minimal, complete and verifiable example",
"main": "index.js",
"dependencies": {},
"devDependencies": {
"chai": "^4.0.1",
"mocha": "^3.4.2"
},
"scripts": {
"test": "mocha -u bdd"
},
"author": "GolezTrol",
"license": "ISC"
}
test/test-foo.js, containing the test. The only thing I added is the first line with require. Before, the browser included the file and Foo was global.
I echoed sut, giving me 5 and sut.should giving me undefined.
var Foo = require('../src/foo.js').Foo;
describe('Foo', function(){
it('should flurp gnip snop', function() {
var sut = Foo.flurp();
console.log(sut); // 5
console.log(sut.should); // undefined
sut.should.be.closeTo(5.00000, 0.00001);
});
});
src/foo.js, the actual unit being tested. In the old setup, Foo would be global (or actually add itself as a property to another global, but that's irrelevant now). I changed this, so it is exported as exports.Foo, so I can require it. This basically works, because I do get '5' in the test.
exports.Foo = function(){}; // Export Foo
var Foo = exports.Foo;
// Give Foo a method
Foo.flurp = function(){
return 5;
}
The output I get from the test shows 'Foo' (the describe), 5 (the logged result) and undefined (the logged value of sut.should). After that, it obviously shows the formal output that the test has failed:
Foo
5
undefined
<clipped for brevity>
1) Foo should flurp gnip snop:
TypeError: Cannot read property 'be' of undefined
at Context.<anonymous> (test\test-foo.js:9:15)
Alternative
I can change all existing unit tests, by adding this line:
var expect = require('chai').expect;
and changing the syntax of the assert to
expect(sut).to.be.closeTo(5.00000, 0.00001);
This is a feasible alternative, since I only got a few dozens of tests. But I'm still interested in finding an answer to the question above.
You need to call the should method to add all should prototype at the beginning
let should = chai.should();
Related
I'm trying to write tests for an old codebase of mine. It uses the isbn package from NPM, which is tiny but does the trick. But whenever I write tests that involve the module, it disappears. That is to say - the value of the module is set to {}.
I've written up two files to try and isolate this issue. I just can't figure out how this test is failing.
First file, isbnTest.js:
const { ISBN } = require("isbn");
function isbnExists() {
return ISBN !== undefined;
}
console.log(isbnExists());
module.exports = {
isbnExists,
};
Pretty simple:
import the module,
one function that just checks if the module has been successfully imported,
log the results, and
export the tester function.
Running this file from the console logs
true
But what happens when we run this code from within Jest?
The second file, ./isbnTest.test.js:
const { isbnExists } = require("./isbnTest.js");
test("isbn should exist", () => {
expect(isbnExists()).toBe(true);
});
When I run npm test with these two files, the test fails.
FAIL
./isbnTest.test.js
✕ isbn should exist (4ms)
● isbn should exist
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
2 |
3 | test("isbn should exist", () => {
> 4 | expect(isbnExists()).toBe(true);
| ^
5 | });
6 |
at Object.<anonymous> (isbnTest.test.js:4:24)
console.log isbnTest.js:7
false
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
It seems as though Jest must be doing some custom importing stuff that's somehow missing this module. Almost like it's being replaced with an empty mock? But I really don't know.
I'd love to remove the isbn package from my program, but without any tests I don't feel confident that I can ensure I won't break anything.
EDIT:
A commenter has pointed out that this doesn't reproduce, which means there's something askew on my machine. Can anyone provide as guess as to what that might be? Deleting and reinstalling the NPM modules doesn't do the trick. I don't think I have any jest config files.
After some further investigation, the problem is being caused by this line in the module:
var exports = typeof window === 'object' && window ? window: module.exports;
If I comment that out, Jest picks it up fine.
I'm trying to build a desktop app for the first time, using the Electron framework, and I'm trying to use the Trilogy module. However, several errors keep popping out.
Basically, the main idea of my code is to have a button that enters a SQL database and checks whether the table "DATA" exists. (I know it's kind of lame, but I'm trying to test out the concept here so bear with me).
My main.js code is just the exact code found in the beginner tutorial, and seemed to be working fine before I imported Trilogy. The dependencies portion of my package.json was as follows:
"dependencies": {
"electron": "^2.0.16",
"sql.js": "^0.5.0",
"trilogy": "^1.4.5"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron ."
},
"devDependencies": {}
The head of my HTML code imported the script "tri.js", and then the body of my HTML code called that with:
<button onclick="search()">Produce Table</button>
<div id="table">table</div>
The file for "tri.js" contains the following code:
require('trilogy');
const db = new Trilogy('./storage.db');
function search()
{
var model = "THIS DOESN'T WORK";
document.getElementById('table').innerHTML = model;
if (db.hasModel('DATA')) {
model = "YES";
}
else {
model = "NO";
}
document.getElementById('table').innerHTML = model;
}
When this code is run using npm start, the outputted text in the div becomes "THIS DOESN'T WORK". I attempted to run it on my browser, but my browser wouldn't recognize "require" and "import" (I tried using both statements), with the error messages "Can't find variable require" and "Import calls expect exactly one argument", respectively. When the button is clicked, it then says "Cannot access uninitialized variable" at the line when I call the db.hasModel() function.
When I tried removing the import and require statement, and loading it straight into the HTML first, it outputs the error that "undefined is not a constructor".
Does anybody have any idea how to implement this so that I could do what I want to do? Or if not, any suggestions on how to further debug this would also be welcome. Thanks.
I'm using the expect.js library with my mocha unit tests. Currently, I'm requiring the library on the first line of each file, like this:
var expect = require('expect.js');
describe('something', function () {
it('should pass', function () {
expect(true).to.be(true); // works
});
});
If possible, I'd like to remove the boilerplate require code from the first line of each file, and have my unit tests magically know about expect. I thought I might be able to do this using the mocha.opts file:
--require ./node_modules/expect.js/index.js
But now I get the following error when running my test:
ReferenceError: expect is not defined
This seems to make sense - how can it know that the reference to expect in my tests refers to what is exported by the expect.js library?
The expect library is definitely getting loaded, as if I change the path to something non-existent then mocha says:
"Error: Cannot find module './does-not-exist.js'"
Is there any way to accomplish what I want? I'm running my tests from a gulp task if perhaps that could help.
You are requiring the module properly but as you figured out, the symbols that the module export won't automatically find themselves into the global space. You can remedy this with your own helper module.
Create test/helper.js:
var expect = require("expect.js")
global.expect = expect;
and set your test/mocha.opts to:
--require test/helper
While Louis's answer is spot on, in the end I solved this with a different approach by using karma and the karma-chai plugin:
Install:
npm install karma-chai --save-dev
Configure:
karma.set({
frameworks: ['mocha', 'chai']
// ...
});
Use:
describe('something', function () {
it('should pass', function () {
expect(true).to.be(true); // works
});
});
Thanks to Louis answer and a bit of fiddling around I sorted out my test environment references using mocha.opts. Here is the complete setup.
My project is a legacy JavaScript application with a lot of "plain" js files which I wish to reference both in an html file using script tags and using require for unit testing with mocha.
I am not certain that this is good practice but I am used to Mocha for unit testing in node project and was eager to use the same tool with minimal adaptation.
I found that exporting is easy:
class Foo{...}
class Bar{...}
if (typeof module !== 'undefined') module.exports = { Foo, Bar };
or
class Buzz{...}
if (typeof module !== 'undefined') module.exports = Buzz;
However, trying to use require in all the files was an issue as the browser would complain about variables being already declared even when enclosed in an if block such as:
if (typeof require !== 'undefined') {
var {Foo,Bar} = require('./foobar.js');
}
So I got rid of the require part in the files and set up a mocha.opts file in my test folder with this content. The paths are relative to the root folder:
--require test/mocha.opts.js
mocha.opts.js content. The paths are relative to the location of the file:
global.assert = require('assert');
global.Foo = require("../foobar.js").Foo;
global.Bar = require("../foobar.js").Bar;
global.Buzz = require("../buzz.js");
I've been trying to create a Smart Package for the SkelJS framework.
The file is being loaded by the browser but when I try and access the object it exports it says its undefined. I'm using the following code in package.js:
Package.describe({
summary: "SkelJS for Meteor"
});
Package.on_use(function (api) {
api.use('jquery', 'client');
api.add_files(['skel.js'], 'client');
api.export('skel', 'client');
});
Also trying to access Package.skeljs.skel returns undefined as well.
In smart.json I'm using:
{
"name": "skeljs",
"description": "SkelJS for Meteor",
"homepage": "",
"author": "Giles Butler (http://giles.io)",
"version": "0.1.0",
"git": ""
}
I know SkelJS has been loaded because it logs to the console no configuration detected, waiting for manual init but then when I try and run skel.init() it returns undefined.
Any help or tips would be really appreciated.
Thanks
Giles
You also need to modify the first line of skel.min.js/skel.js
Within packages variable scoping still applies so you have to remove the var keyword if you want the file to let other files (such as package.js for api.export) access its variables.
The fix would be to change:
var skel=function() ....
to
skel=function() ....
I've installed node-qunit (stable) from npm, but can't seem to get any tests working. My source files don't seem to be included in scope.
./source/myscript.js:
var myObj = {
a : true
}
./test/tests.js:
test("that a is true", function () {
ok(myObj.a);
});
./test/runner.js:
var runner = require('qunit');
runner.run({
code : './source/myscript.js',
tests : './test/tests.js'
});
./Makefile:
test :
<tab>node ./test/testrunner.js
.PHONY: install test
If I run make test, I get a 'ReferenceError: myObj is not defined' error. The source file does run, because it can throw errors. It just doesn't seem to be included in the global scope as it should. It doesn't work if I do it from the command line, as per the instructions in the node-qunit readme. Anyone have any idea how to get this working?
You're not exporting anything. Behind the scenes, node-qunit is using require to load the specified modules. To expose variables when a module is required, you have to add them to the exports object (or assign your own object to the exports variable)
(There's also a syntax error - ; in the object literal)
This works for me:
./source/myscript.js:
exports.myObj = {
a: true
}
./test/tests.js:
QUnit.module('tests')
test("that a is true", function () {
ok(myObj.a)
})
./test/runner.js:
var runner = require('qunit')
runner.run({
code : './source/myscript.js'
, tests : './test/tests.js'
})