Resemblejs in jest hangs - node.js

I'm using ResembleJS for image comparison. I can get it to run when I run it in a standalone script. Here's the code:
var compareImages = require('resemblejs/compareImages');
var fs = require('fs');
var path = require('path');
// The parameters can be Node Buffers
// data is the same as usual with an additional getBuffer() function
async function getDiff() {
var img = path.join(__dirname, 'small.jpg');
const data = await compareImages(
fs.readFileSync(img),
fs.readFileSync(img)
);
console.log(data);
fs.writeFileSync('./output.png', data.getBuffer());
}
getDiff();
Everything works as expected.
But when I run the comparison inside of a test in with the jest framework, it hangs and eventually times out. At first I thought maybe it was just running really slow, so I set my max timeout in jest to be 1 minute. Still failed. So I set my test image to be 1 pixel so it's the simplest test. Still wouldn't finish.
Running from a docker container with Node 8.9.4 (which is what comes from the docker hub node:8). Running jest 22.0.4.
Anybody else have issues running these two together?
I know Resemblejs runs tests with Jest, so not sure what could be causing the issue.

could you please post the code for your tests ?
Are you sure you are returning something from your test block ? In order for an test not to hang you need to return a promise which will resolve before the timeout. Below two examples
test("test", () => {
// test is done when writeFile resolves
return new Promise((resolve, reject) => {
fs.writeFile("path", "encoding", (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
});
test("test", async function () {
// test is done after the assertion
const result = await fetch();
expect(result).toBe(); // test;
});

I had a similar problem with slow tests with Jest, React and Docker (but I'm not using Resemblejs).
I found the solution on Github:
And for me solution was simply add "roots": ["./src"] to jest.config.js

Related

How to persist() when using nockNack with jest and Node?

I am currently working on some unit tests for an express app.
I am using "jest": "^29.4.1", "nock": "^13.3.0",.
The tests I am writing use nockBack.
Imagine I have 3 separate test files that run the code below. The first 2 properly run, save a nock fixture in the proper directory and then re-run just fine. As soon as I introduce a 3rd test; it runs and passes the first time (and saves a fixture etc...) but if I re-run the 3rd test it fails with this error error: Error [NetworkingError]: Nock: No match for request.... I read in the docs that a way to alleviate this is to use the persist() method BUT this is not documented for nockBack only for methods using nock to make calls to pseudo endpoints. I am testing 3rd party api calls that need to go out initially on the netowrk and then subsequent calls will be pulled from the fixtures.
I tried clearing interceptor use by adding these to all my tests:
beforeEach(() => nock.cleanAll());
afterEach(() => nock.cleanAll());
But this does not help to make the 3rd test pass when re-running.
I also tried adding persist() like so: const { nockDone } = await nockBack('post-data.json').persist(); <---- but this fails since it's not a recognized method.
Is there a way to make this work when using nockBack?
Test 1
const nockBack = require('nock').back;
const path = require('path');
const { getPosts } = require('./post');
nockBack.fixtures = path.join(__dirname, '__nock-fixtures__');
nockBack.setMode('record');
test('return a list of posts by a user', async () => {
const userId = 1;
const { nockDone } = await nockBack('post-data.json');
const data = await getPosts(userId);
expect(data.length).toBeGreaterThan(0);
data.forEach((post) => {
expect(post).toEqual(
expect.objectContaining({
userId,
})
);
});
nockDone();
});

How to run a node async function locally?

I'm attempting to write a Node async function and run test it locally. I have this function (using nano for CouchDB):
async function calldb() {
console.log("entering calldb")
const q = {
... query def ...
};
try {
console.log("before await")
const response = await nano.db.find(q)
console.log("after await")
} catch (e) {
return { Error: e}
}
console.log(response);
return response;
}
I want to test locally, so I'm doing npx run-func getGoods.js calldb. This yields:
npx run-func index.js calldb
npx: installed 1 in 0.91s
entering calldb
before await
The first console log runs, but then it doesn't wait around for the response from the db.
How can I test this locally to see if I am actually connecting to the Couch database? How can I get the return from the db call to log to console?
If you look at the code of the library that you indicate (https://github.com/DVLP/run-func/blob/master/index.js), it does not wait for an async function.
If you want to use that library you would need to change the code.

mocha test failing with " MongoError: server sockets closed"

My mocha tests are failing with:
MongoError: server XXXX sockets closed
I have a workaround how to fix them:
const https = require('https');
const server = https.createServer(..);
close() {
mongoose.disconnect(); // <-------- I will comment this line
this.server.close();
};
I would comment out the line mongoose.disconnect(); and my test suite starts working. I would like to clean up after my tests too. Each of my test files recreates server and starts from the scratch. It seems like the error appears because there needs to be some 'waiting' before the next test file executes.
How can I correct this error?
Solution - Captain Hook to the rescue!
If I understand correctly, you wish to startup and cleanup your server after the tests. You also have a series of repetitive tasks you need to do before and after each test.
Mocha has the perfect solution for you: Say hello to Mr. Hook!
Mocha hooks are functions that you can run both before all tests, after all tests, or before each test and after each test:
https://mochajs.org/#hooks
The documentation is pretty complete and I really do recommend it. I your case however, since you are dealing with databases, you probably will be dealing with async hooks.
Sounds complex? Don't worry!
This is how normal sync hooks work:
describe('hooks', function() {
before(function() {
// runs before all tests in this block
});
after(function() {
// runs after all tests in this block
});
beforeEach(function() {
// runs before each test in this block
});
afterEach(function() {
// runs after each test in this block
});
//tests
it("This is a test", () => {
assert.equal(1, 1);
});
});
async hooks only have one difference: they have a parameter done, which is called once your task is finished. Lets assume that we are setting up a DB that takes 1.5 seconds to setup. We want to do this before all the tests, and we only want to do it once.
Let's assume this is our listen function from our DB:
const listen = callback => {
setTimeout(callback, 1500);
};
So after 1.5 seconds, it calls the callback function signalizing it is ready for action.
Now lets see how we would make an async hook:
describe('hooks', function() {
let myDB;
before( done => {
myDB = newDB();
myDB(done);
});
//tests
});
And that's it! Hope it helps!

Make Cordova wait for async hook to finish

In my Cordova project, I have a hook which does RequireJS optimization (r.js) on after_prepare. That optimization is inherently asynchronous, so my hook code returns before all optimization is fully finished.
For example, this causes issues when running cordova run browser: On the first page load, optimization has not finished yet and the site looks broken.
Is there a way to make the Cordovoa build process to block until a certain hook fires a callback? Or can the optimizer be run in a blocking/sync way?
An alternative I could think of is using a different process for optimization and busy-wait in the main for it to finish, but that looks like an overkill and bad practice to me.
You can use the built-in promise module to block Cordova from proceeding until the hook has resolved.
Something along these lines:
#!/usr/bin/env node
var deferral;
function doSomethingAsync(){
somethingAync
.success(function(){
deferral.resolve();
})
.fail(function(err){
deferral.reject(err);
});
}
module.exports = function(ctx) {
deferral = ctx.requireCordovaModule('q').defer();
doSomethingAsync();
return deferral.promise;
};
You don't need to call context, you can simply return a Promise from within the module.exports function
module.exports = context => {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000);
});
};
I tested and it works. The problem arises because in Cordova versions => 9 you cannot use context.requireCordovaModule('q')
If you don't want to use Promise, just do
module.exports = context => {
var deferral = require('q').defer();
doSomethingAsync(() => {
deferral.resolve();
});
return deferral.promise;
};

How can I build my test suite asynchronously?

I'm trying to create mocha tests for my controllers using a config that has to be loaded async. Below is my code. However, when the mocha test is run, it doesn't run any tests, displaying 0 passing. The console.logs are never even called. I tried doing before(next => config.build().then(next)) inside of the describe, but even though the tests run, before is never called. Is there a way to have the config be loaded one time before any tests are run?
'use strict';
const common = require('./common');
const config = require('../config');
config
.build()
.then(test);
function test() {
console.log(1);
describe('Unit Testing', () => {
console.log(2);
require('./auth');
});
}
You should run Mocha with the --delay option, and then use run() once you are done building your test suite. Here is an example derived from the code you show in the question:
'use strict';
function test() {
console.log(1);
describe('Unit Testing', () => {
console.log(2);
it("test", () => {
console.log(3);
});
});
// You must use --delay for `run()` to be available to you.
run();
}
setTimeout(test, 1000);
I'm using setTimeout to simulate an asynchronous operation. Using --delay and run() allows you to build a suite that is the result of an asynchronous computation. Note, however, that the suite must be built in one shot. (You cannot have an asynchronous process inside describe that will make calls to it. This won't work.)
One thing you should definitely not do is what rob3c suggests: calling describe or it (or both) from inside a hook. This is a mistake that every now and then people make so it is worth addressing in details. The problem is that it is just not supported by Mocha, and therefore there are no established semantics associated with calling describe or it from inside a hook. Oh, it is possible to write simple examples that work as one might expect but:
When the suite becomes more complex, the suite's behavior no longer corresponds to anything sensible.
Since there are no semantics associated with this approach, newer Mocha releases may handle the erroneous usage differently and break your suite.
Consider this simple example:
const assert = require("assert");
const p = Promise.resolve(["foo", "bar", "baz"]);
describe("top", () => {
let flag;
before(() => {
flag = true;
return p.then((names) => {
describe("embedded", () => {
for (const name of names) {
it(name, () => {
assert(flag);
});
}
});
});
});
after(() => {
flag = false;
});
it("regular test", () => {
assert(flag);
});
});
When we run it, we get:
top
✓ regular test
embedded
1) foo
2) bar
3) baz
1 passing (32ms)
3 failing
// [stack traces omitted for brevity]
What's going on here? Shouldn't all the tests pass? We set flag to true in the before hook for the top describe. All tests we create in it should see flag as true, no? The clue is in the output above: when we create tests inside a hook, Mocha will put the tests somewhere but it may not be in a location that reflects the structure of the describe blocks in the code. What happens in this case is that Mocha just appends the tests created in the hook the the very end of the suite, outside the top describe, so the after hook runs before the dynamically created tests, and we get a counter-intuitive result.
Using --delay and run(), we can write a suite that behaves in a way concordant with intuition:
const assert = require("assert");
const p = Promise.resolve(["foo", "bar", "baz"]).then((names) => {
describe("top", () => {
let flag;
before(() => {
flag = true;
});
after(() => {
flag = false;
});
describe("embedded", () => {
for (const name of names) {
it(name, () => {
assert(flag);
});
}
});
it("regular test", () => {
assert(flag);
});
});
run();
});
Output:
top
✓ regular test
embedded
✓ foo
✓ bar
✓ baz
4 passing (19ms)
In modern environments, you can use top-level await to fetch your data up front. This is a documented approach for mocha: https://mochajs.org/#dynamically-generating-tests
Slightly adapting the example from the mocha docs to show the general idea:
function fetchData() {
return new Promise((resolve) => setTimeout(resolve, 5000, [1, 2, 3]));
}
// top-level await: Node >= v14.8.0 with ESM test file
const data = await fetchData();
describe("dynamic tests", function () {
data.forEach((value) => {
it(`can use async data: ${value}`, function () {
// do something with data here
});
});
});
This is nice as it is on a per-file basis, and doesn't involve you taking on management responsibility of the test runner as you do with --delay.
The problem with using the --delay command line flag and run() callback that #Louis mentioned in his accepted answer, is that run() is a single global hook that delays the root test suite. Therefore, you have to build them all at once (as he mentioned), which can make organizing tests a hassle (to say the least).
However, I prefer to avoid magic flags whenever possible, and I certainly don't want to have to manage my entire test suite in a single global run() callback. Fortunately, there's a way to dynamically create the tests on a per-file basis, and it doesn't require any special flags, either :-)
To dynamically create It() tests in any test source file using data obtained asynchronously, you can (ab)use the before() hook with a placeholder It() test to ensure mocha waits until before() is run. Here's the example from my answer to a related question, for convenience:
before(function () {
console.log('Let the abuse begin...');
return promiseFn().
then(function (testSuite) {
describe('here are some dynamic It() tests', function () {
testSuite.specs.forEach(function (spec) {
it(spec.description, function () {
var actualResult = runMyTest(spec);
assert.equal(actualResult, spec.expectedResult);
});
});
});
});
});
it('This is a required placeholder to allow before() to work', function () {
console.log('Mocha should not require this hack IMHO');
});

Resources