Mocha Chai HTTP post request not working - mocha.js

The following test is not working with mocha-chai, it is able to to get the input request but throws the error message.
it('/hb : ', function (done) {
return chai.request(app)
.post('/hb')
.send({"a":1 })
.then(function (res) {
expect(err).to.be.null;
expect(res).to.have.status(200);
// { ah: { rt: [Object] }, ad: { mojo: 1 } } }
//console.log("CAlling DOne ........... +");
done();
}, function (err) {
//console.log(err);
throw err;
});
});
Output:
Web Requests : /hb : :
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

The functions that chai-http adds to chai return promises. In your code you return the promise, which is good. However, you also declare your test to take the a parameter: function (done). This would be fine if you did not return the promise, but returning the promise is really the better mechanism here. When you declare your test to take a parameter, Mocha ignores the return value from the test, and so the promise is ignored. So just remove your use of done.
Here's an example that reproduces the error you had in your original code with err being undefined in the function you pass to then.
'use strict';
var app = require('./server');
var chai = require('chai');
chai.use(require('chai-http'));
var expect = chai.expect;
it('/hb', function () {
return chai.request(app)
.post('/hb')
.send({a: 1})
.then(function (res) {
expect(err).to.be.null;
expect(res).to.have.status(200);
});
});
If the server returns a 200 status, then you'll get this on the console:
1) /hb
0 passing (26ms)
1 failing
1) /hb:
ReferenceError: err is not defined
at test.js:13:20
If the server returns a 400 status, the output would be:
1) /hb
0 passing (24ms)
1 failing
1) /hb:
Error: Bad Request
at Test.Request.callback (node_modules/superagent/lib/node/index.js:792:17)
at IncomingMessage.<anonymous> (node_modules/superagent/lib/node/index.js:990:12)
at endReadableNT (_stream_readable.js:913:12)

you need to add following:
.set('content-type', 'application/x-www-form-urlencoded')
you can reference this question over Post request via Chai

Related

How to repeat, circle XHR requests, handle multiple XHR requests in Cypress

How to make through an interval requests before tests?
I tried 2 ways to retry requests but either was failing;
I need to upload a file, waiting till one got imported successfully
On the first step i upload a file to my server in cypress
before( ()=> {
//my custom POST command
cy.form_request(url, data)
.then(({id}) => {
Then i wait for id of the uploaded file
check_It_Till_Success_It(id);
})
})
Then the received id i pass into a new request to verified its status on the server and need to repeat the request till the file processing is finished.
At the solution below it says
CypressError: cy.wait() only accepts aliases for routes.
The alias: 'check_it_request' did not match a route.
function check_It_Till_Success_It(id) {
function checkRequest() {
cy.request("GET", "http://localhost:28080/admin/api/catalog/import/status/" + id)
.then(({status}) => {
if (status === "FINISHED" || status === "FAILED") {
clearInterval(check_It);
} else {
console.log('retry one more time');
}
}).as('check_it_request');
cy.wait("#check_it_request");
}
checkRequest();
const check_It = setInterval(checkRequest, 1000);
}
or here is another my solution through a recursive requesting:
function check_It_Till_Success_It(id) {
return (
cy.request("GET", BASE_URL + "/admin/api/catalog/import/status/" + id)
.then(({status}) => {
if (status === "FINISHED" || status === "FAILED") {
console.log('success');
} else {
console.log('retry one more time');
setTimeout(() => check_It_Till_Success_It(id), 1000)
}
})
)
}
but it throws an error:
Uncaught CypressError: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.
What am i doing wrong?
I found my mystake because of the use of native JS tools as setTimeout, setInterval.
Cypress doesnt allow to use them and replaces with controllable methods: cy.clock and cy.tick
So i took the recursion implementation and replaced with the methods above and my code became:
function check_It_Till_Success_It(id) {
cy.request("GET", BASE_URL + "/admin/api/catalog/import/status/" + id)
.then(resp => {
const status = resp.body.status;
if (status === "FINISHED" || status === "FAILED") {
console.log('success');
} else {
console.log('retry one more time');
cy.clock();
cy.tick(1000);
check_It_Till_Success_It(id)
}
})
}
Offtopic note: I'm new with Cypress and as i understood it replaces the most of the js native features so it's needed to look the docs much closer (BINGO!) or look at issue section because some JS specific feature just crash Cypress without any notification or catched error, for example: FormData object crashed Cypress'es request method.

How do I blend a promise with an observable?

I'm having trouble promises and observables. I have a handful of http requests which are defined in a package using promises. In the rest of my code I am using observables for various things, including other http calls. In one particular section I am checking to see if the user's bearer token is expired and if so then I get a new token and then proceed with the rest of the call.
if (!token || token.exp < Math.round((new Date()).getTime() / 1000)) {
from(this._store.refreshBearerToken())
.pipe(flatMap(resp => {
let newToken = resp.data;
newToken.exp = (new Date()).getTime() / 1000 + newToken.expires_in;
localStorage.setItem('token', JSON.stringify(newToken))
options = options || {};
options.headers = new HttpHeaders({
"Authorization": `${newToken.token_type} ${newToken.access_token}`,
"Content-Type": "application/json"
});
return this._http$.request<T>(method, url, options as Object).pipe(share());
}));
}
Bearer Token method:
async refreshBearerToken() {
const response = await this._q2.sources.requestExtensionData({
route: "refreshBearerToken"
});
console.log(response);
return response;
}
Since this._store.refreshBearerToken returns a promise I wrapped the call in a from to convert it to an observable. This compiles but when it runs I get "Cannot read property 'pipe' of undefined".
How can I convert this promise to an observable so that I can refresh the token and then continue with the rest of the call?
Edit:
I am importing from via import { Observable, from } from "rxjs";.
So, I thought the error was coming from the line .pipe(flatMap(resp =>... but I was wrong. The error is coming from the method which is calling this.
GetInitialLinkList(): Observable<Institution[]>
{
let base = { 'MemberId': localStorage.getItem('memberId') };
let ins = localStorage.getItem("initialInstitutionList");
if (ins)
{
return of(JSON.parse(ins));
}
return this._settingsService.get().pipe(
flatMap(settings =>
{
this._settings = settings;
return this._api.request<Institution[]>("Post", `${this._settings.mea}/GetInitialLinkList`, { body: base })
.pipe(
retry(1),
catchError(this.handleError)
)
.pipe(flatMap(instList =>
{
localStorage.setItem("initialInstitutionList", JSON.stringify(instList));
return of(instList);
}))
}));
}
and that is being subscribed to inside my component:
private GetLinkList()
{
this.showWaiting.emit(true);
this._data.GetInitialLinkList().subscribe((result) =>
{
this.initialList = result;
this.showWaiting.emit(false);
});
}
From what Brandon said (I forgot to return /facepalm...) I added the return so I have return from(this._store.refreshBearerToken()) which changed my error to
ERROR Error Code: undefined
Message: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
defaultErrorLogger # core.js:6014
Can you show the actual error and the line in the code that the error occurs on? Also show where and how you import from.
I notice your code snippet does not return the observable it builds up via from(...).pipe(...) nor does it subscribe to it. It might help to show how your code actually uses this observable.

Problems with $httpBackend.verifyNoOutstandingExpectation()

I have recently started writting unit tests using Karma + Karma-jasmine but I am having problems with the following tests:
describe("WEBSERVICE:", function () {
var webservice,
$httpBackend,
authRequestHandler,
webserviceURL = "http://localhost:8006/";
beforeEach(inject(function (Webservice, $injector) {
webservice = Webservice;
$httpBackend = $injector.get("$httpBackend");
authRequestHandler = $httpBackend
.when("GET", webserviceURL + "users/login")
.respond(200, "ok");
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it("should EXISTS", function () {
expect(webservice).toBeDefined();
});
it("should throw a WebserviceError if we are not logged in" , function () {
expect(function () {
webservice.item("negs", "RPT");
}).toThrow(webserviceAuthenticationError);
});
it("should NOT HAVE credentials when instantiated", function () {
expect(webservice.hasCredentials()).toBeFalsy();
});
it("should log in when valid credentials are given", function () {
$httpBackend.expectGET("users/login");
webservice.withCredentials("sam", "password");
});
});
It appears to be the following which creates the problem since all tests pass when I remove it:
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
I was just wondering if anyone could help me with this.
Thanks a lot.
The reason you having problems is with
$httpBackend.verifyNoOutstandingExpectation();
is due to your last test
it("should log in when valid credentials are given", function () {
$httpBackend.expectGET("users/login");
webservice.withCredentials("sam", "password");
});
having unsatisfied requests which you can see in this jsfiddle
Error: Unsatisfied requests: GET users/login
If you comment out
$httpBackend.verifyNoOutstandingExpectation()
your first three tests pass but the last one is amber as there is no expectations, see this fiddle.
WEBSERVICE:
should EXISTS
should throw a WebserviceError if we are not logged in
should NOT HAVE credentials when instantiated
SPEC HAS NO EXPECTATIONS should log in when valid credentials are given
In the AngularJS documentation it says
verifyNoOutstandingExpectation();
Verifies that all of the requests defined via the expect api were made. If any of the requests were not made, verifyNoOutstandingExpectation throws an exception.
You will need to restructure that test so that
webservice.withCredentials("sam", "password");
makes a request through $httpBackend

Cannot submit form with supertest and mocha

I am using supertest and mocha to test a nodejs application. One of the things users can do is to submit a very simple form, which is picked up by the node server and parsed using formidable.
Here is the mocha test code:
var should = require('should'),
express = require('express'),
app = require('../app.js'),
request = require('supertest'),
csrfToken,
sessionId,
cookies = [];
describe('Post Handler', function(){
it('Uploads new post', function(done){
var req = request(app).post('/post?_csrf=' + csrfToken);
req.cookies = cookies;
req
.type('form')
.send({fieldTitle: 'autopost'})
.send({fieldContent: 'autocontent'})
.send({contentType: 'image/png'})
.send({blobId: 'icon_23943.png'})
.expect(200)
.end(function(error, res){
console.log('here');
done();
});
});
csrfToken retrieves a csrf token from the server, since I am using the csurf module and every POST method requires a csrf token. cookies stores the session cookie that is provided by the node server so I can persist the session between requests.
The form is processed by the following code:
//Takes HTTP form posted by client and creates a new post in the Db
exports.postPostUpload = function (req, res) {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
console.log(err);
if (err) res.redirect(303, '/error');
else {
var new_post = new post_model.Post().createNewPost(fields);
new_post.setUserId(req.session.passport.user.userId);
new_post.uploadPostToDb(function (error, result) {
if (error) return res.status(500).end();
else {
if (new_post.media.contentType.indexOf('video') !== -1) {
addMessageToEncodingQueue(new_post, function (error, result, response) {
if (error) {
errorHelper.reportError({
stack: new Error().stack,
error: error
});
res.status(500).end();
}
else res.status(200).send(new_post.cuid);
});
}
else return res.status(200).send(new_post.cuid);
}
});
}
});
}
My current problem is, that once the form handler executes the line form.parse(req, function (err, fields, files) {, nothing happens. Formidable does not return error, it just does not return anything. Consequently, the mocha test never receives a reply from the server, and eventually the socket hangs and the test crashes. Needless to say, the form is successfully submit if you do it manually via the website.
There must be an error in the way supertest/mocha are executing this test, but I have not been able to find it. Any pointers are highly appreciated.

Intern ajax testing with node.js

I'm using intern with node.js, trying to set up intern for ajax testing. The server code below serves direct GET requests, but XHR request by Intern doesn't seem to reach to it. I suspect the problem is something to do with proxyUrl setup for the Node.
server/main.js: Node/express
...
app.get('/data', function(request, response, next){
if(request.xhr)
{
var data = dfs.readFileSync("src/server/data.json");
response.render(data, {
root: root,
error: new Error('Cant read file')
});
}
else
next();
});
...
app.listen(8001);
http_proxy.createServer(function(req,res, proxy){
proxy.proxyRequest(req,res, {host:'localhost', port:8001});
}).listen(9000);
intern.hello.js: (unit test code)
...
'async test': function () {
var dfd = this.async(1000);
request('/data').then(dfd.callback(function (data) {
assert.strictEqual(data, 'hello world');
}, dfd.reject.bind(dfd)));
}
intern config:
...
proxyPort:9000,
proxyUrl: 'http://localhost:8001/',
...
intern error:
Warning: FAIL: async test (1015ms)
Error: Timeout reached on main - wait - async test
at Error (<anonymous>)
at new ErrorCtor (.../node_modules/intern/node_modules/dojo/errors/create.js:13:21)
at null._onTimeout (.../node_modules/intern/lib/Test.js:164:21)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
2/3 tests passed
2/3 tests passed Use --force to continue.

Resources