Integration testing with Nuxt and Jest - jasmine

I wish to render a page using Nuxt's renderAndGetWindow in order to test the values returned by my API.
Here's how I do it:
// Nuxt instance
let nuxt = null;
// Our page to test
let homePage = null;
beforeAll(async (done) => {
// Configuration
const rootDir = resolve(__dirname, '../..');
let config = {};
config = require(resolve(rootDir, 'nuxt.config.js'));
config.rootDir = rootDir; // project folder
config.env.isDev = false; // dev build
config.mode = 'universal'; // Isomorphic application
nuxt = new Nuxt(config);
await new Builder(nuxt).build();
nuxt.listen(3001, 'localhost');
homePage = await nuxt.renderAndGetWindow('http://localhost:3001/');
});
Which gives me 2 distinct errors:
console.error node_modules/jest-jasmine2/build/jasmine/Env.js:157
Unhandled error
console.error node_modules/jest-jasmine2/build/jasmine/Env.js:158
TypeError: setInterval(...).unref is not a function
And
Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.
at mapper (node_modules/jest-jasmine2/build/queue_runner.js:41:52)
I get this ever since I switched from Ava to Jest.
Am I handling my rendering wrong?

unref
The default test environment for Jest is a browser-like environment through jsdom.
unref is a special function provided by Node. It is not implemented in browsers or in jsdom, but it is implemented in the "node" test environment in Jest.
It looks like testing a Nuxt app requires both a Node environment to start a server, and a jsdom environment to test the resulting UI.
This can be done by setting the test environment to "node" and initializing a window using jsdom during the test setup.
timeout
Jest will "wait if you provide an argument to the test function, usually called done". This applies to test functions and setup functions like beforeAll.
Your beforeAll function has an argument done that is never called. Jest will wait until either done is called or the timeout configured with jest.setTimeout expires (defaults to 5 seconds).
You are using an async function and are using await on what looks to be the asynchronous part of the function so you don't need done. Change your beforeAll function to not take any parameters and that will prevent Jest from waiting for done to be called.
In my tests starting the Nuxt server takes quite a while so you can pass a timeout value as an additional parameter to beforeAll to increase the timeout for just that function.
Here is an updated test with these changes:
/**
* #jest-environment node
*/
// TODO: Set the environment to "node" in the Jest config and remove this docblock
// TODO: Move this to a setup file
const { JSDOM } = require('jsdom');
const { window } = new JSDOM(); // initialize window using jsdom
const resolve = require('path').resolve;
const { Nuxt, Builder } = require('nuxt');
// Nuxt instance
let nuxt = null;
// Our page to test
let homePage = null;
beforeAll(async () => {
// Configuration
const rootDir = resolve(__dirname, '../..');
let config = {};
config = require(resolve(rootDir, 'nuxt.config.js'));
config.rootDir = rootDir; // project folder
config.env.isDev = false; // dev build
config.mode = 'universal'; // Isomorphic application
nuxt = new Nuxt(config);
await new Builder(nuxt).build();
nuxt.listen(3001, 'localhost');
homePage = await nuxt.renderAndGetWindow('http://localhost:3001/');
}, 20000); // Give the beforeAll function a large timeout
afterAll(() => {
nuxt.close();
});
describe('homepage', () => {
it('should do something', () => {
});
});

Related

Why is my koa application timing out when testing a route with Jest/Supertest

Summary of Problem
Receiving : Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout when trying to run a test with Jest and supertest.
Specs
Koa2 project, Jest/Supertest testing, Babel 7.9.0 recommended configuration
What I've tried
I have a simple test from the same file running which I omitted from the code below for brevity. I've also tried sending an HTTP request from the browser - this file is imported & 'listen'ed in a server file. The request is failing because it is blocked by a CORS policy - I think this is a problem for another day and isn't affecting my test timing out.
I also tried removed .callback() from the supertest(..) call:
const response = await supertest(app).post('/save-material');
at which point I get TypeError: app.dress is not a function.
Here is the content of my test file:
process.env.NODE_ENV = 'test';
const app = require('../../src/server/app.js')
const supertest = require('supertest')
test('save-material returns response', async() => {
const response = await supertest(app.callback()).post('/save-material');
expect(response.status).toBe(200);
expect(response.body.status).toBe('success');
expect(response.body.msg).toBe('Material saved')
});
Here is the content of the imported file (app.js) from above:
require('#babel/register'); // not entry point - but is entry point for some tests
const Koa = require('koa');
var Router = require('koa-router')
const app = new Koa();
const router = new Router();
router
.post('/save-material', async(ctx) => {
ctx.response = {
status: 'success',
msg: 'Material saved'
}
return ctx;
})
app.use(router.routes());
app.use(router.allowedMethods());
module.exports = app;

How to wait for WebSocket STOMP messages in Cypress.io

In one of my tests I want to wait for WebSocket STOMP messages. Is this possible with Cypress.io?
If the websocket you'd like to access is being established by your application, you could follow this basic process:
Obtain a reference to the WebSocket instance from inside your test.
Attach an event listener to the WebSocket.
Return a Cypress Promise that is resolved when your WebSocket receives the message.
This is a bit difficult for me to test out, absent a working application, but something like this should work:
In your application code:
// assuming you're using stomp-websocket: https://github.com/jmesnil/stomp-websocket
const Stomp = require('stompjs');
// bunch of app code here...
const client = Stomp.client(url);
if (window.Cypress) {
// running inside of a Cypress test, so expose this websocket globally
// so that the tests can access it
window.stompClient = client
}
In your Cypress test code:
cy.window() // yields Window of application under test
.its('stompClient') // will automatically retry until `window.stompClient` exists
.then(stompClient => {
// Cypress will wait for this Promise to resolve before continuing
return new Cypress.Promise(resolve => {
const onReceive = () => {
subscription.unsubscribe() // clean up our subscription
resolve() // resolve so Cypress continues
}
// create a new subscription on the stompClient
const subscription = stompClient.subscribe("/something/you're/waiting/for", onReceive)
})
})

How do I find the server on my IBM cloud mocha test?

I can get the test to run on the cloud, but it is failing. However, it works local. I think it is because I don't have the right server address. I tried myserver.bluemix.net, localhost:5001 and the null that works local. I can't seem to find the address.
my unit test:
process.env.NODE_ENV = 'test';
var chai = require('chai');
var chaiHttp = require('chai-http');
var app = require('../index');
var cfenv = require('cfenv');
var should = chai.should();
var expect = chai.expect;
chai.use(chaiHttp);
describe('Conversation', function() {
var serviceBaseUrl = '';
if (process.env.test_env == 'cloud') {
serviceBaseUrl
= 'http://' + '127.0.0.1:5001';
}
it ('should return message', function(done){
chai.request(app)
.post(serviceBaseUrl + '/api/v1/conversation')
.send({input: "test", ConverationId: ""})
.end(function (err, res) {
res.status.should.equal(200);
console.log(res.body);
done();
});
});
});
this is the error:
Server running at http://127.0.0.1:5001
Conversation
1) should return message
double callback!
0 passing (33ms)
1 failing
1) Conversation
should return message:
Uncaught TypeError: Cannot read property 'status' of undefined
at test/test-conversation.js:27:12
at Test.Request.callback (/home/pipeline/79a4adb4-e686-494a-9974-3c5860240fcb/node_modules/superagent/lib/node/index.js:615:12)
at ClientRequest.<anonymous> (/home/pipeline/79a4adb4-e686-494a-9974-3c5860240fcb/node_modules/superagent/lib/node/index.js:567:10)
at Socket.socketErrorListener (_http_client.js:309:9)
at emitErrorNT (net.js:1281:8)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickCallback (internal/process/next_tick.js:98:9)
If this is a unit test, you should use mocks in order to isolate your testing environment. The problem is that your localhost is going to have a different base url than when your app is deployed to the cloud.
Consider using a library like nock to mock your api requests.
If you are doing and/or want to do integration tests, you can set the base url with something like this:
const base = process.env['ROUTE'] || 'http://localhost:3000/route';
(Where process.env['ROUTE'] could be something like 'https://app.mybluemix.net/route'.)

promise delay in mocha

I am learning sinon currently. My codes:
const bluebird = require('bluebird');
const sinon = require('sinon');
const sinonTest = require('sinon-test')(sinon);
sinon.test = sinonTest;
describe('xxx', function _test() {
this.timeout(2000);
it('should', sinon.test(function() {
return new bluebird.Promise( (resolve, reject) => {
try {
console.log('123');
resolve();
} catch ( err ) {
reject(err);
};
})
.then( () => console.log('456') )
.delay(100)
.then( () => console.log('789') )
.then(function() {
})
}));
});
output:
xxx
123
456
Why the above code times out and stuck in delay? Thanks
UPDATE
const bluebird = require('bluebird');
const sinon = require('sinon');
const sinonTest = require('sinon-test')(sinon);
sinon.test = sinonTest;
describe('xxx', function _test() {
this.timeout(2000);
it('should', sinon.test(function() {
return bluebird
.delay(100)
.then( () => console.log('789') );
}));
});
Output:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves
UPDATE
Thanks #Louis. Setting useFakeTimers works fine.
But I am just confused. Why in my project, there are no problems with the existing tests where useFakeTimers set to true by default? If useFakeTimers set true, promise delay cannot be used in sinonTest()?
By the way, I had this problem when upgrading sinon from 1.17.6 to 2.4.1.
Thanks
By default the sandboxes that Sinon creates have their configuration set so that the sandbox configuration option useFakeTimers is true. (Search for defaultConfig in this documentation page.)
This means that while the sandbox is in effect, the clock appears to be stopped, and Bluebird's delay never resolves. You tell sinon-test to create sandboxes without fake timers by passing a 2nd parameter when you configure it. This 2nd parameter is actually a configuration object for Sinon sandboxes:
const sinonTest = require('sinon-test')(sinon,
{ useFakeTimers: false });
I have not tried it, but from eyeballing the code, it looks like you could use multiple configurations at the same time if you need some tests to use fake timers and some to not use fake timers:
const sinonTest = require('sinon-test');
const wrapper = sinonTest(sinon, { useFakeTimers: false });
const wrapperWithTimers = sinonTest(sinon);
You just need to use the right wrapper for the needs of the test.
You added the question:
But I am just confused. Why in my project, there are no problems with the existing tests where useFakeTimers set to true by default? If useFakeTimers set true, promise delay cannot be used in sinonTest()?
By default useFakeTimers is true, but that won't cause a problem unless you have code that depends on the clock moving forward to work properly. I have many test suites where I use sandboxes and where I did not take care to turn off the fake timers and they work fine. Fake timers do not generally prevent asynchronous functions from running. If you do fs.readFile while the sandbox is in effect, for instance, it should work just fine. It just affects functions that depend on the clock, like setTimeout, setInterval and Date.
Bluebird's delay method is affected because it calls setTimeout.

Webdriverio Node.js Mocha Chai test skips describe block

I am running this test and it seems that when the test get's to the function portion of my describe block, it skips the whole thing and gives a false positive for passing.
// required libraries
var webdriverio = require('webdriverio');
var describe = require('describe');
var after = require('after');
console.log("Lets begin");
describe('Title Test for google site', function() {
console.log("MARTY!!");
// set timeout to 10 seconds
this.timeout(10000);
var driver = {};
console.log("before we start");
// hook to run before tests
before( function (done) {
// load the driver for browser
console.log("before browser");
driver = webdriverio.remote({ desiredCapabilities: {browserName: 'firefox'} });
driver.init(done);
});
it('should load correct page and title', function () {
// load page, then call function()
return driver
.console.log("before site")
.url('http://www.ggogle.com')
// get title, then pass title to function()
.getTitle().then( function (title) {
// verify title
(title).should.be.equal("google");
// uncomment for console debug
// console.log('Current Page Title: ' + title);
});
});
});
// a "hook" to run after all tests in this block
after(function(done) {
driver.end(done);
});
console.log ("Fin");
This is the output I get
Lets begin
Fin
[Finished in 0.4s]
As you can see it skips everything else.
This is wrong and should be removed:
var describe = require('describe');
var after = require('after');
Mocha's describe and after are added to the global space of your test files by Mocha. You do not need to import them. Look at all the examples on the Mocha site, you won't find anywhere where they tell you to import describe and its siblings.
To get Mocha to add describe and its siblings, you need to be running your test through mocha. Running node directly on a test file won't work. And for mocha to be findable it has to be in your PATH. If you installed it locally, it is (most likely) not in your PATH so you have to give the full path ./node_modules/.bin/mocha.

Resources