- From: Tomasz Pluskiewicz <tomasz@t-code.pl>
- Date: Tue, 24 Jun 2014 14:47:17 +0200
- To: Dave Longley <dlongley@digitalbazaar.com>
- Cc: Tomasz Pluskiewicz <tomasz@t-code.pl>, public-linked-json@w3.org
Hi Dave Thanks very much for such a detailed walkthrough. And sorry about a sloppy fiddle. I guess I was a little bit in a hurry. Anyways, mixing your suggestions into my actual code I managed to wrap jsonld.js in a promise by using the a deferred object from $q.defer and rejecting/resolving in jsonld's callbacks: I've quickly bumped into a problem with the $httpBackend mock. When jsonld tries to get a remote document, which references another remote context, the $httpBackend.flush() fails with message '[$rootScope:inprog] $digest already in progress'. That has something to do with On a second thought it occured to me that there may not be any a good reason to use the $http service fo documentLoader. Do you think? However I still wanted to be able to mock remote calls and fiddling some more I simply do the callback with manually preset responses. Also I found what it takes to wrap jsonld in "angular-friendly" promises... If you're interested do have a look at my updated code [1] (still didn't use jasmine-as-promised, because I haven't found a CORS-happy version). The important bits is the use of $q.defer() and $rootScope.$apply(). Maybe this helps someone :) Regards, Tom [1] http://jsbin.com/besav/5/edit?js,console,output On Thu, Jun 19, 2014 at 6:20 PM, Dave Longley <dlongley@digitalbazaar.com> wrote: > Hi Tom, > > There were several problems with the fiddle. I've updated it to > something that works [1] with some caveats. > > So, first, in the original fiddle, there were some trivial problems: > > 1. Setting jsonld.documentLoader was commented out. > 2. The loader did not return anything (it needed to return a promise). > > Then, there were more complicated problems: > > The JSON-LD API is asynchronous and, for whatever reason, > Jasmine/AngularJS-mocks is not playing nicely with it. This results in a > variety of issues: > > 1. In order for the promise returned by $http.get() to get resolved, you > must call $httpBackend.flush() -- but you must only do so *after* > $http.get() has been called. Since you don't know which turn of the > event loop the document loader will be called on, you can't do this > easily. That means either breaking some abstractions and passing > $httpBackend to an initialization method on the controller or setting > some vars and calling wait functions to watch for them to change. It's a > mess. To be clear: when you call promises.expand(), it, in effect, > "schedules" the expansion algorithm to be run later and returns > immediately. Similarly scheduling occurs with the document loader at > some later point. That means that when the TestController constructor > returns (and therefore, when beforeEach returns), none of the URL > loading/expansion/etc. has been called yet. > > 2. Promises that are external to Jasmine and AngularJS-mocks don't seem > to get resolved. This may be due to whatever Jasmine/AngularJS-mocks > tries to do to manage scheduling when various bits of JS are run. Since > it doesn't have control over external APIs (eg: JSON-LD), however, this > is causing some kind of interference with its normal operation. If you > replace the JSON-LD promises API with a callback-based one, as I have in > the fiddle link [1], then everything works just fine. I don't know > enough about/haven't explored the internals of Jasmine or > AngularJS-mocks to figure out exactly what's going on here. > > It may be that the real solution lies in using some different tools -- > either something that is intended to make Jasmine work with promises > (see jasmine-as-promised [2]) or with some entirely different test suite > that plays more nicely (maybe mocha). > > Anyway, with some really ugly hacks, that fiddle works now. > > -Dave > > [1] http://jsfiddle.net/R5acr/13/ > [2] https://www.npmjs.org/package/jasmine-as-promised > > On 06/19/2014 07:23 AM, Tomasz Pluskiewicz wrote: >> On Thu, Jun 19, 2014 at 1:10 AM, Dave Longley >> <dlongley@digitalbazaar.com> wrote: >>> On 06/18/2014 05:20 PM, Tomasz Pluskiewicz wrote: >>>> Hi >>>> >>>> I'm trying to use the jsonld with Angular and in tests I want to >>>> replace the default documentLoader with $http service so that I can >>>> mock the responses. >>>> >>>> I assumed that because $http already returns a promise it would be >>>> enough to simply use a function like >>>> >>>> jsonld.documentLoader = function (url) { >>>> return $http.get(url); >>>> } >>>> >>>> as replacement for whatever is currently set. >>>> >>>> Unfortunately it doesn't work. What's would be correct way to do that? >>> >>> That's because the value that promise resolves to isn't what is required >>> by the JSON-LD API spec. It requires that the promise resolve to a >>> "RemoteDocument": >>> >>> http://www.w3.org/TR/json-ld-api/#idl-def-RemoteDocument >>> >>> I didn't test this, but it should be pretty close to what you want: >>> >>> jsonld.documentLoader = function(url) { >>> return $http.get(url).then(function(response) { >>> return { >>> contextUrl: null, >>> document: response.data, >>> documentUrl: url >>> } >>> }); >>> }; >>> >>> Hopefully that works for you. >>> >> >> Unfortunately it's not that easy. I'm not very experienced with >> JavaScript or Angular. I created a fiddle [1] similar to my failing >> code. >> >> As is, XHR fails, because it's a CORS request. If you uncomment the >> two lines two weird things happen (or don't happen). First, $http mock >> fails saying there aren't any pending requests and none of the >> console.log called in callbacks are invoked. Which is weird, because >> it means that even the $http promise is never resolved. I tried to >> debug it but I get lost somewhere inside jsonld/angular. Also there >> isn't any other exception being caught bu Chrome dev tools. >> >> Any ideas? Hasn't someone already done that? >> >> Thanks, >> Tom >> >> [1] http://jsfiddle.net/tpluscode/R5acr/12/ >> >>> >>> -Dave >>> >>> -- >>> Dave Longley >>> CTO >>> Digital Bazaar, Inc. >>> >> >> > > > -- > Dave Longley > CTO > Digital Bazaar, Inc. >
Received on Tuesday, 24 June 2014 12:48:46 UTC