I'm testing with jasmine and it's working fine locally. However Travis CI is returning undefined for all the API tests. Example
4) Server GET /api/v1/orders Status 200
Message:
Expected undefined to be 200.
Stack:
Error: Expected undefined to be 200.
at
Snippet from the tests
describe('GET /api/v1/orders', function () {
var data = {};
beforeAll(function (done) {
Request.get('http://localhost:3001/api/v1/orders', function (error, response, body) {
data.status = response.statusCode;
data.body = JSON.parse(body);
data.number = data.body.length;
done();
});
});
it('Status 200', function () {
expect(data.status).toBe(200);
});
it('It should return three Items', function () {
expect(data.number).toBe(3);
});
});
Could the problem be from the 'http://localhost:3001/api/v1/orders' URL?
You don't seem to be starting your server anywhere so localhost:3001 isn't available.
A good solution would be to use something like supertest. It would allow you to do something like so:
app.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const routes = require('./api/routes/routes.js')(app);
// We listen only if the file was called directly
if (require.main === module) {
const server = app.listen(3001, () => {
console.log('Listening on port %s...', server.address().port);
});
} else {
// If the file was required, we export our app
module.exports = app;
}
spec.routes.js
'use strict';
var request = require('supertest');
var app = require('../../app.js');
describe("Test the server", () => {
// We manually listen here
const server = app.listen();
// When all tests are done, we close the server
afterAll(() => {
server.close();
});
it("should return orders properly", async () => {
// If async/await isn't supported, use a callback
await request(server)
.get('/api/v1/orders')
.expect(res => {
expect(res.body.length).toBe(3);
expect(res.status).toBe(200);
});
});
});
Supertest allows you to make requests without relying on a specific port/url/other.
Related
i am working on a chatapp project that needs a real time chatting so i have used socketio in my server side which is written in nodejs and than used socketio-client in my main chatapp react-native project.
But now a problem is coming my socket is not initializing. I'm not able to connect my server with my main app. I am using socketio and socketio client my both the socket version are same 4.5.1 but it's not even connecting. I have tried to use old version of socket but its also not working and I have also tried to change my localhost port to 4000 but it's also not working.
My server code:
const express = require('express');
var bodyParser = require('body-parser');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const port = process.env.PORT || 3000;
require('./src/config/database')
const user_routes = require('./src/user/users.routes');
app.use(bodyParser.urlencoded({extended: true}))
app.use(express.json())
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
app.use('/User', user_routes)
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('send_message',(data)=>{
console.log("received message in server side",data)
io.emit('received_message',data)
})
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
server.listen(port, () => {
console.log( `Server running at http://localhost:${port}/`);
});
My app socketservice file code:
import io from 'socket.io-client';
const SOCKET_URL = 'http://localhost:3000'
class WSService {
initializeSocket = async () => {
try {
this.socket = io(SOCKET_URL, {
transports: ['websocket']
})
console.log("initializing socket", this.socket)
this.socket.on('connect', (data) => {
console.log("=== socket connected ====")
})
this.socket.on('disconnect', (data) => {
console.log("=== socket disconnected ====")
})
this.socket.on('error', (data) => {
console.log("socekt error", data)
})
} catch (error) {
console.log("scoket is not inialized", error)
}
}
emit(event, data = {}) {
this.socket.emit(event, data)
}
on(event, cb) {
this.socket.on(event, cb)
}
removeListener(listenerName) {
this.socket.removeListener(listenerName)
}
}
const socketServcies = new WSService()
export default socketServcies
Where I have marked it should be connected = true but it's false in the dev console I have done console log so check that it's connecting or not and I can see that it's not connecting. How to make it connect?
There is no error in my app or server I have checked many times and my server is also running when I am running my app.
Answering my own question
The problem was i was using android emulator and android in an emulator can't connect to localhost you need to use the proxy ip so when i add http://10.0.2.2:3000 in const SOCKET_URL = 'http://10.0.2.2:3000' than its working fine
credit goes to gorbypark who told me this in discord
I'm assuming that your front and back runs in localhost. The documentation says that if the front-end is in the same domain as the back-end, you don't need to use the URL. Since you have the options parameter declared, you can use the default argument window.location in first place:
class WSService {
initializeSocket = async () => {
try {
this.socket = io(window.location, {
transports: ['websocket']
})
console.log("initializing socket", this.socket)
this.socket.on('connect', (data) => {
console.log("=== socket connected ====")
})
this.socket.on('disconnect', (data) => {
console.log("=== socket disconnected ====")
})
this.socket.on('error', (data) => {
console.log("socekt error", data)
})
} catch (error) {
console.log("scoket is not inialized", error)
}
}
emit(event, data = {}) {
this.socket.emit(event, data)
}
on(event, cb) {
this.socket.on(event, cb)
}
removeListener(listenerName) {
this.socket.removeListener(listenerName)
}
}
Don't specify the host/port for socket-io to connect to. It can figure it out on its own.
Per documentation, it tries to connect to window.location if no URL is specified as an argument.
So instead of
this.socket = io(SOCKET_URL, {
transports: ['websocket']
})
Just do
this.socket = io()
I am not sure it works with other arguments. You could try like this
this.socket = io(undefined, {
transports: ['websocket']
})
I'm trying to set up testing for various routes in my Express server that require connectivity to my MongoDB database.
I'm not sure how to structure the Jest file in order to allow for testing. In my normal index.js file, I'm importing the app, and running app.listen within the connect .then call, like this:
const connect = require("../dbs/mongodb/connect");
connect()
.then(_ => {
app.listen(process.env.PORT, _ => logger.info('this is running')
})
.catch(_ => logger.error('The app could not connect.');
I've tried running the same setup in my test.js files, but it's not working.
For example:
const connect = require("../dbs/mongodb/connect");
const request = require("supertest");
const runTests = () => {
describe("Test the home page", () => {
test("It should give a 200 response.", async () => {
let res = await request(app).get("/");
expect(res.statusCode).toBe(200);
});
});
};
connect()
.then(_ => app.listen(process.env.PORT))
.then(runTests)
.catch(err => {
console.error(`Could not connect to mongodb`, err);
});
How is it possible to wait for a connection to MongoDB before running my tests?
So, turns out there were a few changes that I had to make. Firstly, I had to load in my .env file before running the tests. I did this by creating a jest.config.js file in the root of my project:
module.exports = {
verbose: true,
setupFiles: ["dotenv/config"]
};
Then within the actual testing suite, I'm running beforeEach to connect to the MongoDB server.
const connect = require("../dbs/mongodb/connect");
const app = require("../app");
const request = require("supertest");
beforeEach(async() => {
await connect();
});
describe("This is the test", () => {
test("This should work", async done => {
let res = await request(app).get("/home");
expect(res.statusCode).toBe(200);
done();
})
});
server.js is a simple express.js file that uses jwt tokens. I currently want to test a simple route that will only return the string "Hello World" as shown below
app.get("/", (req, res) => {
res.send("Hello World");
});
The code below is my jest file that is using supertest to send the request along with the valid jwt token
const supertest = require("supertest");
let server, request;
const serverStart = new Promise(resolve => {
server = require("../server.js");
request = supertest(server);
server.on("app_started", () => {
resolve();
});
});
beforeAll(async () => {
await serverStart;
});
afterAll(() => {
server.close();
});
describe("When testing the server.js", () => {
it("Should connect successfully and be able to return a response", async () => {
const response = await request
.get("/")
.set("Authorization", `bearer ${process.env.AUTHTOKEN}`);
expect(response.text).toBe("Hello World");
console.log(response.text);
});
});
When running this jest (after it's timeout of 5 seconds) says Timeout - Async callback was not invoked within the 5000ms timeout specified however, the console.log that I have added after the expect function outputs "Hello World" to the console meaning the request is made and returns a value but it carriers on with the code but is just skipping the expect function
I've also tried this with done() and also using a then() but got the same error both times and I've console logged the time before and after the call and found it only takes a few milliseconds to return a value, so why does the expect not seem to complete the test?
Pretty sure your problem is the app_started event that you are listening to. I don't know where that event is documented. I think you should use listening instead. I'm going to make some assumptions about your server.js file.
The following test passes. I think your tests never actually start because you are listening for an event that will never be fired.
This is the server.js file that I am testing with:
const http = require("http");
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("hello");
});
const server = http.createServer(app);
server.listen(8081);
module.exports = server;
This is my test file server.test.js:
const supertest = require("supertest");
let server, request;
const serverStart = new Promise(resolve => {
server = require("./server.js");
request = supertest(server);
server.on("listening", () => resolve());
});
beforeAll(async () => {
await serverStart;
});
afterAll(() => {
server.close();
});
describe("server", () => {
it("should get hello", async () => {
const response = await request.get("/");
expect(response.text).toBe("hello");
});
});
User zero298 pointed out that the test was failing during the beforeAll() function because server.on() wasn't returning anything. In the end I wrote the promise inside the server.js which resolves after it has started and then exported this promise.
let server;
const serverStart = new Promise(resolve => {
server = app.listen(port, err => {
if (err) {
console.log(err);
}
console.log("Listening on port " + port);
resolve();
});
});
module.exports = app;
module.exports.close = () => server.close();
module.exports.serverStart = serverStart;
and the beforeAll() in server.test.js now looks like
const server = require("../server.js");
let request;
beforeAll(async () => {
await server.serverStart;
request = supertest(server);
});
I want to check a case that certain routes are calling the correct controller use Jest specific (mock or spy).
It is case specific for unit testing. Somebody can help me how to check it use jest. I don't need verify kind of
expect (status code or res object) i need to check if controller have been called.
Thanks!
For instance:
// todoController.js
function todoController (req, res) {
res.send('Hello i am todo controller')
}
// index.spec.js
const express = require('express');
const request = require('request-promise');
const todoController = require('./todoController');
jest.mock('./todoController');
const app = express();
app.get('/todo', todoController)
test('If certain routes are calling the correct controller , controller should to have been called times one.', async() => {
await request({url: 'http://127.0.0.1/todo'})
expect(todoController).toHaveBeenCalledTimes(1);
})
Actually if you search, there are many references out there.
In the following, I share a few ways that I know.
One of the big conceptual leaps to testing Express applications with mocked request/response is understanding how to mock a chained
API eg. res.status(200).json({ foo: 'bar' }).
First you can make some kind of interceptor, this is achieved by returning the res instance from each of its methods:
// util/interceptor.js
module.exports = {
mockRequest: () => {
const req = {}
req.body = jest.fn().mockReturnValue(req)
req.params = jest.fn().mockReturnValue(req)
return req
},
mockResponse: () => {
const res = {}
res.send = jest.fn().mockReturnValue(res)
res.status = jest.fn().mockReturnValue(res)
res.json = jest.fn().mockReturnValue(res)
return res
},
// mockNext: () => jest.fn()
}
The Express user-land API is based around middleware. AN middleware that takes a request (usually called req), a response (usually called res ) and a next (call next middleware) as parameters.
And then you have controller like this :
// todoController.js
function todoController (req, res) {
if (!req.params.id) {
return res.status(404).json({ message: 'Not Found' });
}
res.send('Hello i am todo controller')
}
They are consumed by being “mounted” on an Express application (app) instance (in app.js):
// app.js
const express = require('express');
const app = express();
const todoController = require('./todoController');
app.get('/todo', todoController);
Using the mockRequest and mockResponse we’ve defined before, then we’ll asume that res.send() is called with the right payload ({ data }).
So on your test file :
// todo.spec.js
const { mockRequest, mockResponse } = require('util/interceptor')
const controller = require('todoController.js')
describe("Check method \'todoController\' ", () => {
test('should 200 and return correct value', async () => {
let req = mockRequest();
req.params.id = 1;
const res = mockResponse();
await controller.todoController(req, res);
expect(res.send).toHaveBeenCalledTimes(1)
expect(res.send.mock.calls.length).toBe(1);
expect(res.send).toHaveBeenCalledWith('Hello i am todo controller');
});
test('should 404 and return correct value', async () => {
let req = mockRequest();
req.params.id = null;
const res = mockResponse();
await controller.todoController(req, res);
expect(res.status).toHaveBeenCalledWith(404);
expect(res.json).toHaveBeenCalledWith({ message: 'Not Found' });
});
});
This is only 1 approach to testing Express handlers and middleware. The alternative is to fire up the Express server.
I am using NodeJS. I am checking the response status of https://encrypted.google.com/ . I have a file in my project. Let's call it ,
status.js :-
var https = require('https');
https.get('https://encrypted.google.com/', function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
}).on('error', function(e) {
console.error(e);
});
Now, I also have server.js file and node is running through it.
node server.js
I want to execute the status.js till the nodeserver runs. That means, it should continously check the status of https://encrypted.google.com/. What is the recommended way to do this ?
server.js :-
const express = require('express');
const bodyParser = require('body-parser');
// create express app
const app = express();
// listen for requests
app.listen(3000, () => {
console.log("Server is listening on port 3000");
});
Use a setInterval and execute the code from status.js. When your status is resolved as you want it, clear the interval via clearInterval.
Ok. I think the adding an event emitter was a bit unnecessary. You can try this out. This is the typescript file. For javascript replace the imports with the respective require statements.
server.ts
import express from "express";
import http from 'http';
import { getHttpsRequests } from "./status";
//Create an http server with the express app
const app = express();
const server = new http.Server(app);
let interval;
// listen for requests
server.listen(4300);
server.on('listening', () => {
interval = setInterval(() => {
getHttpsRequests();
}, 1000);
});
//register a close event on server
server.on('close', () => {
console.log('closing server');
clearInterval(interval);
});
status.ts
var https = require('https');
export function getHttpsRequests() {
//your code goes here
https.get('https://encrypted.google.com/', function (res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
res.on('data', function (d) {
process.stdout.write(d);
});
}).on('error', function (e) {
console.error(e);
});
}