Writing an async test with Intern - asynchronous

I am trying to write an Integration test which calls my real service (that returns JSON) and makes sure the format of the JSON is OK.
I get an error
Error: Unable to load http://localhost:7200/users/signoff status: 0
ErrorCtor#http://localhost:9000/resources/www/tests/lib/dojo/errors/create.js:29
onError#http://localhost:9000/resources/www/tests/lib/dojo/request/xhr.js:133
I've got a service that has the actual functions to interact with the server and it returns promises from every function. My test looks like this.
define([
'intern!bdd',
'intern/chai!expect',
'app/services/myService'
], function (bdd, expect, MyService) {
with (bdd) {
describe('Service Tests', function () {
var service;
before(function () {
service = MyService.getInstance();
});
it('should sign user off', function(){
var dfd = this.async(2000);
service.signUserOff().then(dfd.callback(function (data) {
expect(data).to.exist;
expect(data.status).to.exist;
}), dfd.reject.bind(dfd));
});
});
}
});
service.signOff() makes a call to the real service and then returns a promise. I have tried this with Firefox and PhantomJS both and I keep getting this error. The weird thing is, the URL in the error works fine if loaded manually in the browser.
I wonder if this is something to do with Intern not being able to load the request/xhr.js and therefore throwing this error?

The request that you are making is considered a cross-site request, so you need to either make sure your server correctly responds with the appropriate CORS headers for such a request, or you need to set up a reverse proxy that ensures that the XHR requests are occurring through the same origin.

Related

Insert new collection after function runs on server

When I return the geocode from googles API I'm trying to save it into my database. I've been trying to use the code below, to just insert a Test document with no luck. I think it has something to do with meteor being asynchronous. If I run the insert function before the googleMapsClient.geocode function it works fine. Can someone show me what I'm doing wrong.
Meteor.methods({
'myTestFunction'() {
googleMapsClient.geocode({
address: 'test address'
}, function(err, response) {
if (!err) {
Test.insert({test: 'test name'});
}
});
}
});
I see now where you got the idea to run the NPM library on the client side, but this is not what you really want here. You should be getting some errors on the server side of your meteor instance when you run the initial piece of code you gave us here. The problem is that the google npm library runs in it's own thread, this prevents us from using Meteor's methods. The easiest thing you could do is wrap the function with Meteor.wrapAsync so it would look something like this.
try {
var wrappedGeocode = Meteor.wrapAsync(googleMapsClient.geocode);
var results = wrappedGeocode({ address : "testAddress" });
console.log("results ", results);
Test.insert({ test : results });
} catch (err) {
throw new Meteor.Error('error code', 'error message');
}
You can find more info by looking at this thread, there are others dealing with the same issue as well
You should run the googleMapsClient.geocode() function on the client side, and the Test.insert() function on the server side (via a method). Try this:
Server side
Meteor.methods({
'insertIntoTest'(json) {
Test.insert({results: json.results});
}
});
Client side
googleMapsClient.geocode({
address: 'test address'
}, function(err, response) {
if (!err) {
Meteor.call('insertIntoTest', response.json);
}
});
Meteor Methods should be available on the both the server and client sides. Therefore make sure that your method is accessible by server; via proper importing on /server/main.js or proper folder structuring.
(If a method contains a secret logic run on the server, it should be isolated from the method runs on both server & client, though)

AngularJS $httpBackend asynchronous response

I'm trying to mock the back-end for an AngularJS(1.3.8)-app with ngMockE2E as replacement until the back-end code has been written.
I'm using already existing services that also query other data, however they return a promise. I am aware that ngMockE2E is supposed to be synchronous, however I wanted to see if there's a way to do it asynchronously first.
Looking around the web I found this and put the mocking-related code into its own seperate module to see if this approach works.
$httpBackend.whenAsync('projects/').respond(function (promise, headers, status) {
var deferred = $q.defer();
_getProjectIndex().then(function (result) {
deferred.resolve(result);
},
function (statusCode) {
console.log(statusCode);
deferred.reject(statusCode);
});
return deferred.promise;
});
When I try to run $httpBackend.whenAsync() the request just seems to 404. Checking the same request with $httpBackend.whenGET() I receive the promise containing the data I requested.
What am I doing wrong?

Meteor http calls limitations

Currently, I use the built-in meteor http method (see http://docs.meteor.com/#http) for issuing http calls, on both my client and my server.
However, I'm experiencing two issues:
is it possible to cancel a request?
is it possible to have multiple query parameters which share the same key?
Are these just Meteor limitations, or are there ways to get both to work using Meteor?
I know I could you jquery on the clientside, and there must be a server-side solution which supports both as wel, but I'd prefer sticking with meteor code here.
"is it possible to cancel a request?"
HTTP.call() does not appear to return an object on which we could call something like a stop() method. Perhaps a solution would be to prevent execution of your callback based on a Session variable?
HTTP.call("GET", url, function(error, result) {
if (!Session.get("stopHTTP")) {
// Callback code here
}
});
Then when you reach a point where you want to cancel the request, do this:
Session.set("stopHTTP", true);
On the server, instead of Session perhaps you could use an environment variable?
Note that the HTTP.call() options object does accept a timeout key, so if you're just worried about the request never timing out, you can set this to whatever millisecond integer you want.
"is it possible to have multiple query parameters which share the same key?"
Yes, this appears to be possible. Here's a simple test I used:
Meteor code:
HTTP.call("GET", "http://localhost:1337", {
query: "id=foo&id=bar"
}, function(error, result) {
// ...
});
Separate Node.js server: (just the basic example on the Node.js homepage, with a console.log line to output the request URL with query string)
var http = require('http');
http.createServer(function(req, res) {
console.log(req.url); // Here I log the request URL, with the query string
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
When the Meteor server is run, the Node.js server logged:
/?id=foo&id=bar
Of course, this is only for GET URL query parameters. If you need to do this for POST params, perhaps you could store the separate values as a serialized array string with EJSON.stringify?

Using tinytest to test Meteor client while the server is running

Is it possible to test the Meteor client while the server is running using tinytest? Here's my example testing the client only:
Tinytest.add("Add object to a collection", function(test) {
var people = new Meteor.Collection("people");
people.insert({"name": "Andrew"}, function(error, id) {
test.isNull(error);
});
});
For a fraction of a second this passes, but then it goes into the state of "waiting". I'm also positive that error is not null.
Meteor.Error {error: 404, reason: "Method not found", details: undefined}
I know this is happening because their is no server for the client to communicate with. When I try to run this test on the server and client, I continue to get the same issue with the client. Is there a way to test the client while the server is running?
Thanks, Andrew
Use new Meteor.Collection with no argument to create a stub collection that doesn't require the server. See the docs on Collections:
If you pass null as the name, then you're creating a local collection. It's not synchronized anywhere; it's just a local scratchpad that supports Mongo-style find, insert, update, and remove operations.
This is an async test, so you'll have to use addAsync.
Tinytest.addAsync("Add object to a collection", function(test, next) {
var people = new Meteor.Collection("people");
people.insert({"name": "Andrew"}, function(error, id) {
test.isNull(error);
next();
});
});
Note the next argument which signals that you are done in the callback.

Meteor.http.call gives not allowed by Access-Control-Allow-Origin

When I try to call an external server for JSON queries in Meteor with the Meteor.http.call("GET") method I get the error message "not allowed by Access-Control-Allow-Origin".
How do I allow my meteor app to make HTTP calls to other servers?
Right now I run it on localhost.
The code I run is this:
Meteor.http.call("GET",
"http://api.vasttrafik.se/bin/rest.exe/v1/location.name?authKey=XXXX&format=json&jsonpCallback=processJSON&input=kungsportsplatsen",
function(error, result) {
console.log("test");
}
);
There are other questions similar to this on StackOverflow.
You're restricted by the server you're trying to connect to when you do this from the client side (AJAX).
One way to solve it is if you have access to the external server, you can modify the header file to allow some, or all origins by:
Access-Control-Allow-Origin: *
However, if you place the call on the server side and not provide a callback function, the call will be made synchronously, thus not with AJAX, and it should succeed.
Here's
Meteor.methods({checkTwitter: function (userId) {
this.unblock();
var result = Meteor.http.call("GET", "http://api.twitter.com/xyz", {params: {user: userId}});
if (result.statusCode === 200) return true
return false;
}});

Resources