diff --git a/lib/angular.dart b/lib/angular.dart index 925307137..3529cf471 100644 --- a/lib/angular.dart +++ b/lib/angular.dart @@ -131,7 +131,6 @@ class AngularModule extends Module { type(CacheFactory, CacheFactory); type(Http, Http); type(UrlRewriter, UrlRewriter); - type(HttpFutures, HttpFutures); type(HttpBackend, HttpBackend); type(BlockCache, BlockCache); type(TemplateCache, TemplateCache); diff --git a/lib/http.dart b/lib/http.dart index c3d814a2a..9944db996 100644 --- a/lib/http.dart +++ b/lib/http.dart @@ -1,11 +1,5 @@ part of angular; -// NOTE(deboer): This should be a generic utility class, but lets make sure -// it works in this case first! -class HttpFutures { - async.Future value(x) => new async.Future.value(x); -} - class UrlRewriter { String call(url) => url; } @@ -36,9 +30,8 @@ class Http { Map> _pendingRequests = >{}; UrlRewriter rewriter; HttpBackend backend; - HttpFutures futures; - Http(UrlRewriter this.rewriter, HttpBackend this.backend, HttpFutures this.futures); + Http(UrlRewriter this.rewriter, HttpBackend this.backend); async.Future getString(String url, {bool withCredentials, void onProgress(ProgressEvent e), Cache cache}) { @@ -64,7 +57,7 @@ class Http { } var cachedValue = cache != null ? cache.get(url) : null; if (cachedValue != null) { - return futures.value(cachedValue); + return new async.Future.value(cachedValue); } var result = backend.request(url, method: method, diff --git a/test/_http.dart b/test/_http.dart index bfafded04..848f48c80 100644 --- a/test/_http.dart +++ b/test/_http.dart @@ -8,7 +8,7 @@ class MockHttp extends Http { Map gets = {}; List futures = []; - MockHttp(UrlRewriter rewriter, HttpBackend backend, HttpFutures futures) : super(rewriter, backend, futures); + MockHttp(UrlRewriter rewriter, HttpBackend backend) : super(rewriter, backend); expectGET(String url, String content, {int times: 1}) { gets[url] = new MockHttpData(content, times); @@ -47,20 +47,6 @@ class MockHttpData { toString() => value; } -class MockHttpFutures extends HttpFutures { - List completersAndValues = []; - Future value(x) { - var completer = new Completer.sync(); - completersAndValues.add([completer, x]); - return completer.future; - } - - trigger() { - completersAndValues.forEach((cv) => cv[0].complete(cv[1])); - completersAndValues = []; - } -} - class MockHttpBackend extends HttpBackend { Map gets = {}; List completersAndValues = []; diff --git a/test/_specs.dart b/test/_specs.dart index a15eb603c..8c9291c66 100644 --- a/test/_specs.dart +++ b/test/_specs.dart @@ -2,6 +2,7 @@ library ng_specs; import 'dart:html'; +import 'dart:async' as dartAsync; import 'package:unittest/unittest.dart' as unit; import 'package:angular/debug.dart'; import 'dart:mirrors' as mirror; @@ -154,6 +155,21 @@ class Logger implements List { noSuchMethod(Invocation invocation) => mirror.reflect(_list).delegate(invocation); } +List _asyncQueue = []; + +nextTurn() { + // copy the queue as it may change. + var toRun = new List.from(_asyncQueue); + _asyncQueue = []; + toRun.forEach((fn) => fn()); +} + +async(Function fn) => + () { + dartAsync.runZonedExperimental(fn, onRunAsync: (asyncFn) => _asyncQueue.add(asyncFn)); + expect(_asyncQueue.isEmpty).toBe(true); + }; + class SpecInjector { Injector moduleInjector; Injector injector; diff --git a/test/_specs_spec.dart b/test/_specs_spec.dart index 6dd7833e9..0a5740194 100644 --- a/test/_specs_spec.dart +++ b/test/_specs_spec.dart @@ -1,4 +1,5 @@ import "_specs.dart"; +import "dart:async"; main() { describe('renderedText', () { @@ -32,6 +33,77 @@ main() { expect(div.html()).toEqual('text'); }); }); + }); + + describe('async', () { + it('should run synchronous code', () { + var ran = false; + async(() { ran = true; })(); + expect(ran).toBe(true); + }); + + + it('should run async code', () { + var ran = false; + var thenRan = false; + async(() { + new Future.value('s').then((_) { thenRan = true; }); + expect(thenRan).toBe(false); + nextTurn(); + expect(thenRan).toBe(true); + ran = true; + })(); + expect(ran).toBe(true); + }); + + + it('should run chained thens', () { + var log = []; + async(() { + new Future.value('s') + .then((_) { log.add('firstThen'); }) + .then((_) { log.add('2ndThen'); }); + expect(log.join(' ')).toEqual(''); + nextTurn(); + expect(log.join(' ')).toEqual('firstThen 2ndThen'); + })(); + }); + + it('shold run futures created in futures', () { + var log = []; + async(() { + new Future.value('s') + .then((_) { + log.add('firstThen'); + new Future.value('t').then((_) { + log.add('2ndThen'); + }); + }); + expect(log.join(' ')).toEqual(''); + nextTurn(); + expect(log.join(' ')).toEqual('firstThen'); + nextTurn(); + expect(log.join(' ')).toEqual('firstThen 2ndThen'); + })(); + }); + + + it('should complain if you dangle callbacks', () { + expect(() { + async(() { + new Future.value("s").then((_) {}); + })(); + }).toThrow(); + }); + + + it('should complain if the test throws an exception', () { + expect(() { + async(() { + throw "blah"; + })(); + }).toThrow("blah"); + }); }); } diff --git a/test/directives/ng_include_spec.dart b/test/directives/ng_include_spec.dart index 82056ae22..ae46c9aca 100644 --- a/test/directives/ng_include_spec.dart +++ b/test/directives/ng_include_spec.dart @@ -8,11 +8,7 @@ main() { beforeEach(beforeEachTestBed((tb) => _ = tb)); - beforeEach(module((AngularModule module) { - module.type(HttpFutures, MockHttpFutures); - })); - - it('should fetch tempalte from url', inject((Scope scope, TemplateCache cache, HttpFutures futures) { + it('should fetch tempalte from url', async(inject((Scope scope, TemplateCache cache) { cache.put('tpl.html', new HttpResponse(200, 'my name is {{name}}')); var element = _.compile('
'); @@ -23,9 +19,10 @@ main() { scope['name'] = 'Vojta'; scope['template'] = 'tpl.html'; }); - futures.trigger(); + + nextTurn(); // load the template from cache. expect(element.text()).toEqual('my name is Vojta'); - })); + }))); it('should support inlined templates', inject((Scope scope) { diff --git a/test/http_spec.dart b/test/http_spec.dart index 288a29cf7..92aca13b8 100644 --- a/test/http_spec.dart +++ b/test/http_spec.dart @@ -20,7 +20,6 @@ main() { var rewriter, futures, backend, cache; beforeEach(() { rewriter = new SubstringRewriter(); - futures = new MockHttpFutures(); backend = new MockHttpBackend(); cache = new FakeCache(); }); @@ -28,7 +27,7 @@ main() { it('should rewrite URLs before calling the backend', () { backend.expectGET('a', VALUE, times: 1); - var http = new Http(rewriter, backend, futures); + var http = new Http(rewriter, backend); var called = 0; http.getString('a[not sent to backed]').then((v) { expect(v).toBe(VALUE); @@ -46,7 +45,7 @@ main() { it('should support pending requests for different raw URLs', () { backend.expectGET('a', VALUE, times: 1); - var http = new Http(rewriter, backend, futures); + var http = new Http(rewriter, backend); var called = 0; http.getString('a[some string]', cache: cache).then((v) { expect(v).toBe(VALUE); @@ -63,8 +62,8 @@ main() { backend.assertAllGetsCalled(); }); - it('should support caching', () { - var http = new Http(rewriter, backend, futures); + it('should support caching', async(() { + var http = new Http(rewriter, backend); var called = 0; http.getString('fromCache', cache: cache).then((v) { expect(v).toBe(CACHED_VALUE); @@ -73,25 +72,24 @@ main() { expect(called).toEqual(0); backend.flush(); - futures.trigger(); + nextTurn(); expect(called).toEqual(1); backend.assertAllGetsCalled(); - }); + })); }); describe('http caching', () { - var rewriter, futures, backend, cache; + var rewriter, backend, cache; beforeEach(() { rewriter = new UrlRewriter(); - futures = new MockHttpFutures(); backend = new MockHttpBackend(); cache = new FakeCache(); }); it('should not cache if no cache is present', () { backend.expectGET('a', VALUE, times: 2); - var http = new Http(rewriter, backend, futures); + var http = new Http(rewriter, backend); var called = 0; http.getString('a').then((v) { expect(v).toBe(VALUE); @@ -114,7 +112,7 @@ main() { it('should return a pending request', inject(() { backend.expectGET('a', VALUE, times: 1); - var http = new Http(rewriter, backend, futures); + var http = new Http(rewriter, backend); var called = 0; http.getString('a', cache: cache).then((v) { expect(v).toBe(VALUE); @@ -135,7 +133,7 @@ main() { it('should not return a pending request after the request is complete', () { backend.expectGET('a', VALUE, times: 2); - var http = new Http(rewriter, backend, futures); + var http = new Http(rewriter, backend); var called = 0; http.getString('a', cache: cache).then((v) { expect(v).toBe(VALUE); @@ -157,8 +155,8 @@ main() { }); - it('should return a cached value if present', () { - var http = new Http(rewriter, backend, futures); + it('should return a cached value if present', async(() { + var http = new Http(rewriter, backend); var called = 0; // The URL string 'f' is primed in the FakeCache http.getString('f', cache: cache).then((v) { @@ -168,10 +166,10 @@ main() { expect(called).toEqual(0); backend.flush(); - futures.trigger(); + nextTurn(); expect(called).toEqual(1); backend.assertAllGetsCalled(); - }); + })); }); }