- From: Dave Longley <dlongley@digitalbazaar.com>
- Date: Tue, 24 Jun 2014 16:08:25 -0400
- To: Tomasz Pluskiewicz <tomasz@t-code.pl>
- CC: public-linked-json@w3.org
On 06/24/2014 08:47 AM, Tomasz Pluskiewicz wrote: > 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. Sure, and no problem. > 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 That happens when $rootScope.$apply() isn't high enough in the stack. If it's too low, you can end up double-scheduling a $digest op. It may be best to just let users of your wrapper call it as needed. I don't know if this causes some issue with the required manual-triggering of promise/deferred resolution during testing though. You'd have to investigate further. > 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? Well, it's certainly not necessary; we use JSON-LD and AngularJS and don't bother with it. It could be useful for testing and mocks as you're trying to do here. > 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 :) I hope so! > > 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. >> > -- Dave Longley CTO Digital Bazaar, Inc. http://digitalbazaar.com
Received on Tuesday, 24 June 2014 20:08:43 UTC