JavaScript single request to two different ports - javascript

I'm testing a script where one function makes an HTTP request and is then called in another function.
The first function is:
export function getFeedData (sub) {
if (getFeedId(sub) === 2) {
return axios.get('http://localhost:4000').then((data) => JSON.parse(data));
}
}
And the second is:
export function isDelay (sub, stop) {
return getFeedData(sub).then((data) => {
return data.entity.filter((entityObj) => {
return entityObj.stop_time_update !== undefined;
});
}).then((newData) => {
console.log(newData);
}).catch((err) => {
console.log(err);
});
}
The reason they're two different functions is that the second will eventually be longer, and I wanted to separate everything out for the sake of simplicity and making my code a bit more declarative.
The tests for these functions currently look like this:
import express from 'express';
import { getFeedId, getFeedData, reverseStop, isDelay } from '../mocks/apiMock';
const app = express();
app.use(express.static('../mocks/MockData.json'));
it('returns json data', (done) => {
app.listen(4000, function () {
expect.assertions(2);
return getFeedData('L').then((data) => {
expect(data).toBeDefined();
expect(data.header.gtfs_realtime_version).toBe('1.0');
});
});
done();
});
it('returns either the delay or time until the next train' , (done) => {
app.listen(4000, function () {
isDelay('L', 'Lorimer St');
});
done();
});
That second test doesn't run because it's trying to listen on a port that's already occupied.
The solution I had in mind would be to pass app.listen() 0 as its first parameter so it listens on a random port. However, I don't know how I could get my axios request to request that specific port. Is there a way to do this? Or perhaps a better solution to my problem? Please be kind as this is my first real independent dive into creating node/express servers, and I'm trying my best to research problems on my own before posting here.

You should only use one specific HTTP server port, e.g :4000.
Then, you should setup your HTTP server like this:
const port = 4000;
let server
beforeAll((done) => {
server = app.listen(port, () => {
done();
})
})
afterAll((done) => {
server && server.close(done)
})
// Your test suites and test cases.
Then you can test your functions and they make HTTP requests to the same endpoint, e.g. http://localhost:4000.

Related

Firebase Functions: Random 404's

I'm using firebase functions on a server for API calls. Everything works fine 70% of the time, but all of a sudden some of my function calls start failing to execute, giving my API a 404, and don't work for the next few hours.
In my StackDriver I can see the function isn't called again when I try. My API just gives me a 404 without ever reaching the server.
Below is one of the calls that fails once in a while. Going to the URL i'm fetching, the GET result always shows up, so I have no clue what the issue is.
API call:
const getCreators = () => {
return window
.fetch(url + '/get-creators', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then((res) => {
console.log(res);
if (res.status === 200) {
return res.json();
} else {
return null;
}
})
.then((data) => {
if (!data || data.error) {
return null;
} else {
return data;
}
});
};
Server code:
const app = express();
app.get('/get-creators', async (req, res) => {
console.log('creators: ');
creators
.find()
.toArray()
.then((result) => {
console.log(result);
res.status(200).send(result);
})
.catch(() => {
console.log('error');
res.send('error');
});
});
app.listen(4242, () => console.log(`Node server listening at https ${4242}!`));
exports.app = functions.https.onRequest(app);
Found it. You don't want the below code on your server:
app.listen(4242, () => console.log(`Node server listening at https ${4242}!`));
I commented this code out, republished, and all is well.
I thought having this didn't make a difference, but apparently once in a blue moon it can and will try to make the server listen locally, which gave me a 404.

Capture all XHR Requests with Cypress.io

When I call the URL, an undefined number of requests are sent.
Now I try to find out if one of the requests contains a certain payload.
cy.server();
cy.visit(url);
cy.route({
method: 'POST',
url: '**/t/e/**',
}).as('xhrRequest');
I have found a similar approach on How to capture all API calls in cypress? so far.
the problem here is that a fixed number of API calls is assumed.
cy.wait(Array(60).fill('#xhrRequest'), { timeout: 30000 }).then((xhrs) => {
xhrs.forEach((res) => {
expect(res.status).not.to.be.null
})
})
How do I get it that all requests are intercepted and fail my test if there is not a single request containing the payload.
I already wrote something like this in puppeteer
let hasSpecialRequest = false;
page.on('request', request => {
if (isSpecialRequest(request)) {
hasSpecialRequest = true;
}
request.continue();
});
await page.setRequestInterception(true);
expect(hasSpecialRequest).to.equal(true);
The system checks whether each request is one of the special requests and sets the variable accordingly. Something like this I try to recreate with Cypress.
You might consider doing cy.exec and run a script in another language and return status from subprocess.
I may have misunderstood the problem but since I got here through my Google expedition maybe this might help someone that had my problem and possibly you.
At first I used the cy.wait(#alias) but could never retrieve all the responses (only one response was being shown and I couldn't figure out how to access ALL the responses). So I ended up immediately storing the responses into another array to access within the test.
let xhrRequests;
function getXhrRequests() {
xhrRequests = [];
cy.intercept('GET', '**', (res) => {
xhrRequests.push(res);
});
return xhrRequests;
}
describe('Some', function () {
it('Thing 1', () => {
let thing1 = getXhrRequests();
cy.visit('http://some.site');
thing1.forEach((res) => {
expect(res.status).not.to.be.null;
})
}
it('Thing 2', () => {
let thing2 = getXhrRequests();
cy.visit('http://some.site/2');
thing2.forEach((res) => {
expect(res.status).not.to.be.null;
})
}
});

How to assure that the Express response comes after the File System terminates the write stream?

In an Express.js API I'm creating a zip file that stores a collection of PDFs that is intended to be passed as a download
I have created the zipfile using the yazl package following the README file, and it's pretty good, the problem comes when I use the pipe to create the createWriteStream, because I don't know how to properly wait until is finished.
Then in my Express route I want to send the file, but this code is executed before the write stream is finished...
This is a piece of code of a Promise function named renderReports inside my repository.js file, after I write the PDFs file I use a loop to added to the yazl's zipFile, then I proceed to create the zip with the fs.createWriteStream
const renderFilePromises = renderResults.map((renderedResult, index) =>
writeFile(`./temporal/validatedPdfs/${invoices[index].id}.pdf`, renderedResult.content)
);
await Promise.all(renderFilePromises);
const zipfile = new yazl.ZipFile();
invoices.map((invoice, index) => {
zipfile.addFile(`./temporal/validatedPdfs/${invoice.id}.pdf`, `${invoice.id}.pdf`)
});
zipfile.outputStream.pipe(fs.createWriteStream("./temporal/output.zip").on('close', () => {
console.log('...Done');
}));
zipfile.end();
resolve();
And the following code is how I use the promise
app.post('/pdf-report', async (req, res, next) => {
const { invoices } = req.body;
repository.renderReports(reporter, invoices)
.then(() => {
res.sendFile('output.zip', {
root: path.resolve(__dirname, './../../temporal/'),
dotfiles: 'deny',
}, (err) => {
if (err) {
console.log(err);
res.status(err.status).end();
}
else {
console.log('Sent:', 'output.zip');
}
});
})
.catch((renderErr) => {
console.error(renderErr);
res.header('Content-Type', 'application/json');
return res.status(501).send(renderErr.message);
});
});
I hope somebody can explain how to approach this
You need to store the write stream in a variable so you can access it. Then, on this variable, wait for the stream‘s finish event. This is emitted by Node.js once the stream is done with writing.

Node.js - How to test HTTPS requests with promise

I started writing unit tests for my nodeJs application so i could learn about this concept.
After writing some basic tests for simple functions (using Mocha and Chai) i want to move on to some more complex tests.
I have written a simple piece of code that can make a request using node's HTTPS module. That code looks like this:
const https = require('https')
module.exports.doRequest = function (params, postData) {
return new Promise((resolve, reject) => {
const req = https.request(params, (res) => {
let body = []
res.on('data', (chunk) => {
body.push(chunk)
})
res.on('end', () => {
try {
body = JSON.parse(Buffer.concat(body).toString())
} catch (e) {
reject(e)
}
resolve(body)
})
})
req.on('error', (err) => {
reject(err)
})
if (postData) {
req.write(JSON.stringify(postData))
}
req.end()
})
}
Now i want to invoke this method with the following parameters:
const PARAMS = {
host: 'jsonplaceholder.typicode.com',
port: 433,
method: 'GET',
path: `/todos/1`,
headers: {
Authorization: 'Bearer 123'
}
}
And make the request like so:
getTodos = (PARAMS) => {
return doRequest(PARAMS).then((result) => {
if (result.errors) { throw result }
return {
'statusCode': 200,
'body': JSON.stringify({ message: result.title }),
}
}).catch((error) => ({
'statusCode': error.statusCode,
'body': JSON.stringify({ message: error.message }),
}
))
}
Now my question is how i can test this bit of code properly. I have looked on how to tackle this with the Nock.js libary but i don't have a good understanding on where to start.
If anyone can point me in the right direction on how to start with writing some tests for this bit of code i will be thankfull.
In general, you would want to black box your HTTP handling, so that as few modules in your application need to care about the details of HTTP as possible.
In the source folder, you'd have one module (e.g. commonhttp.js). You want this to export your HTTP functions, and other modules in your application use them like this:
const commonhttp = require('./commonhttp');
commonhttp.doRequest( ... ).then( ... );
Other modules, like todos.js, and various other modules, will export their own functions using that module, for example:
const commonhttp = require('./commonhttp');
const todos = {
getTodos( ... ) {
return commonhttp.doRequest( ... );
},
createTodo( ... ) {
return commonhttp.doRequest( ... );
},
// etc.
};
module.exports = todos;
For your unit tests, when you test the todos.js module, you want to mock any calls to the commonhttp module; you can use simple mocha + Sinon for this, and spy on the doRequest method. Basically all you're testing is "when I call getTodos, I expect it to make a call to doRequest with these arguments". You'd follow this pattern for all the modules in your application that uses doRequest.
You also, of course, want to test the commonhttp module -- that spec is where Nock might come in handy. It's not strictly necessary, you can also "block-box" the http module, but you have to set up a lot of complicated spies to mimic the behavior of http; instead, writing a spec (using Nock) that says "ok, I call doRequest with these params, that should have made this HTTP call" does make sense.

Sails.js with Socket.io: Blasting events works fine, but broadcasting doesn't

In my frontend I'm using the sails.io.js wrapper. I'm trying to connect to my backend and listen for notifications. This works fine when I'm using blast to send out to all connected sockets, but broadcasting does nothing.
However, joining a room seems to work as the callback from the join function gets executed without any errors.
The frontend part:
import * as socketIoClient from 'socket.io-client'
import * as sailsIo from 'sails.io.js'
const io = sailsIo(socketIoClient)
io.sails.url = 'localhost:1337'
io.sails.environment = process.env.NODE_ENV || 'development'
io.sails.useCORSRouteToGetCookie = false
io.socket.get('/notification/join', (data, jwRes) => {
console.log('Server responded with status code ' + jwRes.statusCode + ' and data: ', data);
})
io.socket.on('notification', data => {
console.log('Server says: ', data);
})
My Sails Controller:
export const join = async (req, res) => {
if (!req.isSocket) {
return res.badRequest();
}
// Join a user specific notification room
sails.sockets.join(req, 'notification', error => {
if (!error) console.log('Everything went fine')
return res.send('Connected') // this works so far
})
// Send events each second
setInterval(() => {
sails.sockets.broadcast('notification', { data: 'Real notification' }) // This never works
sails.sockets.blast('notification', {data: 'BLAST'}) // This works perfectly
}, 1000)
}
Any suggestion on what goes wrong? Like I said, the callback of joining the room gets executed without an error, also the blast call works fine and the frontend is able to receive the message.

Categories

Resources