I'm trying to use sinon-chai with expect but when I try to check if a function is not called, I get:
TypeError: expect(...).to.have.not.been.called is not a function
This is what I tried:
expect(createCompany).not.to.have.been.called();
expect(createCompany).to.not.have.been.called();
expect(createCompany).to.have.not.been.called();
expect(createCompany).to.have.been.not.called();
expect(createCompany).to.have.been.notCalled();
But none of them is working, but I have no problem without the ".not"
My file is starting with:
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
chai.use(sinonChai);
const { expect } = chai;
Ok so I found that this is because of the parens.
So just replace called() by called and it's working.
Related
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;
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', () => {
});
});
i was going through a GraphQL tutorial from udemy,
https://www.udemy.com/introduction-to-graphql-and-apollo-building-modern-apis
And i was going through the guide to operating graphql and graphiql -> apollo -express - server. And got this. This particular error has not been defined in the videos. It is a free tutorial and lecture 9 has this.
Wht to do. i find no solution. Please help.
TypeError: Cannot read property 'startsWith' of undefined
at Object.renderGraphiQL (/home/dell/Desktop/graphql-
tutorial/node_modules/apollo-server-module-
graphiql/src/renderGraphiQL.ts:48:17)
at Object. (/home/dell/Desktop/graphql-tutorial/node_modules/apollo-
server-module-graphiql/src/resolveGraphiQLString.ts:62:10)
at step (/home/dell/Desktop/graphql-tutorial/node_modules/apollo-
server-module-graphiql/dist/resolveGraphiQLString.js:32:23)
at Object.next (/home/dell/Desktop/graphql-
tutorial/node_modules/apollo-server-module-
graphiql/dist/resolveGraphiQLString.js:13:53)
at fulfilled (/home/dell/Desktop/graphql-tutorial/node_modules/apollo-
server-module-graphiql/dist/resolveGraphiQLString.js:4:58)
at
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
renderGraphiQLString.js
This is the line it says has error -->
export function renderGraphiQL(data: GraphiQLData): string {
const endpointURL = data.endpointURL;
const endpointWs =
endpointURL.startsWith('ws://') || endpointURL.startsWith('wss://');
const subscriptionsEndpoint = data.subscriptionsEndpoint;
const usingHttp = !endpointWs;
const usingWs = endpointWs || !!subscriptionsEndpoint;
const endpointURLWs =
usingWs && (endpointWs ? endpointURL : subscriptionsEndpoint);
resolveGraphiQLString.js
export async function resolveGraphiQLString(
query: any = {},
options: GraphiQLData | Function,
...args
): Promise<string> {
const graphiqlParams = createGraphiQLParams(query);
const graphiqlOptions = await resolveGraphiQLOptions(options,
...args);
const graphiqlData = createGraphiQLData(graphiqlParams,
graphiqlOptions);
return renderGraphiQL(graphiqlData);
}
server.js
import express from 'express';
import {graphqlExpress,graphiqlExpress} from 'apollo-server-express';
import bodyParser from 'body-parser';
import schema from './schema.js'
const server = express();
server.use('/graphql', bodyParser.json(), graphqlExpress(schema));
server.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql'
}));
server.listen(4000,() =>{
console.log('listening on port 4000');
});
I was doing the same tutorial and got stuck with the same error. I just now got it working. For me, I had spelled endpointURL as endpointUrl because it seems stupid to me to capitalize acronyms within camel-case, but of course this being a specific key, it has to be spelled right.
For you, the only difference I see in the code is that I think you should pass {schema} to graphqlExpress, but you're passing just schema. So here's how I have it:
server.use("/graphql", bodyParser.json(), graphqlExpress({ schema }))
Your code is not correct. In order to define the graphiql endpoint you need to do this in the following way:
const server = express();
server.use('/graphql', bodyParser.json(), graphqlExpress(schema));
server.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));
Keep in mind you should pass to the graphiqlExpress method the endpointURL of your real graphql endpoint.
Cheers!
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.
I'm trying to use highland in combination with the heroku-client. But internally in the heroku client it uses this, even if I try to bind to bind this, the function gives and error message where there is a refrance to this I'm not able to get it to work.
Right no the code looks like this
const Heroku = require('heroku-client');
const hl = require('highland');
var hk = new Heroku({
token: process.env.HEROKU_API_TOKEN
});
var list = hl.wrapCallback(hk.apps().list.bind(hk));
list().toArray((a) => 'console.log(a)')
So this code snippet fails with the following error message:
...node_modules/heroku-client/lib/resourceBuilder.js:35
if (this.params.length !== pathParams.length) {
^
TypeError: Cannot read property 'length' of undefined
Yo! :-)
You're binding to hk and not what hk.apps() return, which is what the list function depends on (it's a member of what hk.apps() returns)
Try this:
const Heroku = require('heroku-client');
const hl = require('highland');
const hk = new Heroku({
token: process.env.HEROKU_API_TOKEN
});
const hkApps = hk.apps();
const list = hl.wrapCallback(hkApps.list.bind(hkApps));
list().toArray((a) => 'console.log(a)')