mocha: can't use one request for mutlple `it` test - mocha.js

const request = require('supertest');
const server = request('http://localhost:9001');
describe('Get /static/component-list.json', function() {
const api = server.get('/static/component-list.json');
it('should response a json', function(done) {
api.expect('Content-Type', /json/, done);
});
it('200', function(done) {
api.expect(200, done); // This will failed
// server.get('/static/component-list.json').expect(200, done); // This will successed
});
});
when reuse api in the second test case, mocha will raise a Error:
The result of mocha test/api command:
How can I request the url once and use in multiple it case.

Solution
You have to create a new request for each test (each it) that you want to run. You cannot reuse the same request for multiple tests. So
describe('Get /static/component-list.json', function() {
let api;
beforeEach(() => {
api = server.get('/static/component-list.json');
});
Or if you want to reduce the number of requests made, then combine all your checks on the request into a single Mocha test.
Explanation
If you look at the code of supertest, you'll see that when you call an expect method with a callback, expect calls automatically calls end. So this:
api.expect('Content-Type', /json/, done);
is equivalent to this:
api.expect('Content-Type', /json/).end(done);
The end method is provided by superagent, which is what supertest uses to perform requests. The end method is what kicks off the request. It means you are done setting up the request and want to fire it off now.
The end method calls the request method, which is tasked with using Node's networking machinery to produce a Node request object that is used to perform the network operation. The problem is that request caches the Node request is produces but this Node request object is not reusable. So ultimately, a superagent or supertest request cannot be ended twice. You have to reissue the request for each test.
(You could manually flush the cached object between tests by doing api.req = undefined. But I strongly advise against this. For one thing, whatever optimization you might think you'd get is minimal because the network request still has to be made anew. Secondly, this amounts to messing with superagent's internals. It may break with a future release. Third, there may be other variables that hold state that might need to be reset together with req.)

Related

Multiple Observables waiting for single Observable completion on RetryWhen

I am trying to build an app using Oauth2.
There are multiple (GET) calls to API from the frontend and I deal with them like so:
// Call API for data
this.apiGet('/foo?id=bar).pipe(
// If it fails, use refresh token to obtain new access token and try again
retryWhen(x => {
// If there is existing request (Observable), use it
if (this.refreshTokenObservable !== null) {
return this.refreshTokenObservable;
}
// Otherwise make new request (fills this.refreshTokenObservable)
return this.getAccessByRefreshToken();
})
)
This works fine when there is only one apiGet(), however, when using multiple calls one right after another, the refreshTokenObservable variable do not fill quickly enough, causing multiple calls and, subsequently, errors.
Is there any way to prevent this?

Creating Resolvers that work with an external FHIR Server

I am exploring this library
https://github.com/Asymmetrik/graphql-fhir
It does not contain logic for how to implement resolvers for a 3rd party FHIR Server.
Has anyone attempted this?
I'll add some pseudo code below, but that library is essentially a wrapper and has no backend, so you can definitely use it to wrap other FHIR servers. GraphQL resolvers can resolve sync or async. So if we took the patient resolver (https://github.com/Asymmetrik/graphql-fhir/blob/master/src/resources/4_0_0/profiles/patient/resolver.js), for example, and wanted to connect it to a third party server, like HAPI or some other server. You could implement it like so (pseudocode so untested):
module.exports.getPatient = function getPatient(root, args, context = {}, info) {
// args contains the arguments in GraphQL format, note that these may
// not map directly to another FHIR server for naming restriction reasons
// e.g. fooBar in graphql might be foo-bar in REST
// Make an HTTP request, use any http library, for example, fetch
return fetch('some/fhir/server/patient', {
method: 'post',
body: JSON.stringify(args) // remember args may need to be mapped
})
.then(response => response.json())
.then(results => {
// Make sure the response matches what the resolver expects, in this
// case, a single patient
return results;
});
};
There is an example at https://github.com/Asymmetrik/graphql-fhir/blob/master/FAQ.md#resolvers, but that is loading a local patient, you just need to make an HTTP request to some 3rd party server and return the results asynchronously. For handling errors, make sure to check out this as well, https://github.com/Asymmetrik/graphql-fhir/blob/master/FAQ.md#resolvers.

Using the result of an AJAX call as an AMD module [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm using RequireJS while prototyping an application. I'm "faking" a real database by loading a json file via ajax.
I have several modules that need this json file, which I noticed results in multiple http requests. Since I'm already using RequireJS, I thought to myself "hey, why not load this json file as another module". Since a module can return an object, it seemed reasonable.
So I tried this:
// data.js
define(function(require){
const $ = require('jquery')
var data = {}
$.getJSON('/path/to/data.json', function(json_data){
data = json_data
})
// this does not work because getJSON is async
return data
})
// some_module.js
define(function(require){
const my_data = require('data')
console.log(data) // undefined, but want it to be an object
})
I understand why what I'm doing is not working. I'm not sure what the best way to actually do this would be though.
Things I don't want to do:
Change getJSON to async: false
add a while (data == null) {} before trying to return data
Is there an AMD-y want to accomplish what I'm trying to do? I'm sure there's a better approach here.
Edit
I just tried this. It works, but I'm not sure if this is a good or terrible idea:
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data')
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
My concern is (1) browser support (this is a "promise", right?) and (2) if multiple modules do this at the same time, will it explode.
Because this question is specifically referring to using JQuery, you can actually do this without a native promise using JQuery's deferred.then().
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data') // this is a JQuery object
// using JQuery's .then(), not a promise
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
Based on the description of then() in JQuery's docs, it looks like this is using a promise behind the scenes:
As of jQuery 1.8, the deferred.then() method returns a new promise that can filter the status and values of a deferred through a function, replacing the now-deprecated deferred.pipe() method. [...]
Callbacks are executed in the order they were added. Since deferred.then returns a Promise, other methods of the Promise object can be chained to this one, including additional .then() methods.
Since JQuery's .then() does work in IE, I guess they are polyfilling the promise for IE behind the scenes.

Reload page with new context in express

I have a page that lists events, in which admins are can delete individual items with an AJAX call. I want to reload the page when an event is deleted, but I am having trouble implementing it with my current understanding of express' usual req, res, and next.
Here is my current implementation (simplified):
Simple jQuery code:
$(".delete").click(function(e){
$.post("/events/delete",{del:$(this).val()})
})
in my routes file:
function eventCtrl(req,res){
Event.find({}).exec(function(err,events){
...
var context = {
events:events,
...
}
res.render('events',context);
});
}
function deleteCtrl(req,res,next){
Event.findById(req.param("del")).exec(function(err,event){
// delete my event from google calendar
...
event.remove(function(err){
...
return next();
});
});
}
app.get('/events',eventCtrl);
app.post('/events/delete',deleteCtrl,eventCtrl);
When I make a post request with AJAX all the req handlers are called, the events are deleted successfully, but nothing reloads. Am I misunderstanding what res.render() does?
I have also tried using a success handler in my jQuery code when I make the post request, with a res.redirect() from deleteCtrl, but my context is undefined in that case.
on the client side, you are using
$(".delete").click(function(e){
$.post("/events/delete",{del:$(this).val()})
})
this code does not instruct the browser to do anything when the response from the post is received. So nothing visible happens in the browser.
You problem is not located server side ; the server answers with the context object. You are simply not doing anything with this answer.
Try simply adding a successHandler.
Generally speaking this would not be a best practice. What you want to do is reconcile the data. If the delete is successful, then just splice the object out of the array it exists in client-side. One alternative would be to actually send back a refreshed data set:
res.json( /* get the refreshed data set */ );
Then client-side, in the callback, you'd actually just set the data source(s) back up based on the result:
... myCallback(res) {
// refresh the data source(s) from the result
}

Making an Ajax request using data from previous ajax request

I am attempting to write an Angular page to communicate with my Nodejs server, but I have ran into a snag.
I need to use multiple Ajax requests that rely on the data from previous ajax requests to work.
So Ajax request #1 provides data that is used by all other Ajax requests, and Ajax request #2 uses data from ajax request #1 to get the data that Ajax request #3 needs.
Since Angular is asynchronous, how can I make my script wait for the data from the first one before making the next ajax call.
id = ajax()
Wait for data
token = ajax(id)
wait for data
gametoken = ajax(id, token)
wait for data
Chandermani is correct, just remember to make sure to make the variables you need available in the scope that you need it.
var id,token,gametoken;
$http.get('http://host.com/first')
.then(function(result){
id=result;
return $http.get('http://host.com/second/'+id);
}
.then(function(result){
token = result
return $http.get('http://host.com/third'+id+'/'+token);
}
.then(function(result){
gametoken = result;
//Do other code here that requires id,token and gametoken
}
EDIT:
You don't have to chain the promises. If you want to make a call at a later date and you want to make sure the promises have resolved you can use $q.all();
var id,token,gametoken;
var p1 = $http.get('http://host.com/first')
.then(function(result){
id=result;
}
// Later on to make your new second call
$q.all([p1]).then(function(){
//Make second call knowing that the first has finished.
}
$q.all() takes an array so you can put in multiple promises if you want and it will wait until they have all resolved.

Resources