W3C home > Mailing lists > Public > public-linked-json@w3.org > June 2014

Re: Using Angular $http service as documentLoader

From: Dave Longley <dlongley@digitalbazaar.com>
Date: Thu, 19 Jun 2014 12:20:17 -0400
Message-ID: <53A30DC1.8060409@digitalbazaar.com>
To: Tomasz Pluskiewicz <tomasz@t-code.pl>
CC: public-linked-json@w3.org
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 Thursday, 19 June 2014 16:20:43 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 16:18:41 UTC