diff --git a/modules/angular2/src/testing/testing.ts b/modules/angular2/src/testing/testing.ts index 73176eea21..0eaff9ce05 100644 --- a/modules/angular2/src/testing/testing.ts +++ b/modules/angular2/src/testing/testing.ts @@ -126,77 +126,23 @@ function _isPromiseLike(input): boolean { return input && !!(input.then); } -function runInTestZone(fnToExecute, finishCallback, failCallback): any { - var pendingMicrotasks = 0; - var pendingTimeouts = []; - - var ngTestZone = (global.zone) - .fork({ - onError: function(e) { failCallback(e); }, - '$run': function(parentRun) { - return function() { - try { - return parentRun.apply(this, arguments); - } finally { - if (pendingMicrotasks == 0 && pendingTimeouts.length == 0) { - finishCallback(); - } - } - }; - }, - '$scheduleMicrotask': function(parentScheduleMicrotask) { - return function(fn) { - pendingMicrotasks++; - var microtask = function() { - try { - fn(); - } finally { - pendingMicrotasks--; - } - }; - parentScheduleMicrotask.call(this, microtask); - }; - }, - '$setTimeout': function(parentSetTimeout) { - return function(fn: Function, delay: number, ...args) { - var id; - var cb = function() { - fn(); - ListWrapper.remove(pendingTimeouts, id); - }; - id = parentSetTimeout(cb, delay, args); - pendingTimeouts.push(id); - return id; - }; - }, - '$clearTimeout': function(parentClearTimeout) { - return function(id: number) { - parentClearTimeout(id); - ListWrapper.remove(pendingTimeouts, id); - }; - }, - }); - - return ngTestZone.run(fnToExecute); -} - function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | AnyTestFn, testTimeOut: number): void { var timeOut = testTimeOut; if (testFn instanceof FunctionWithParamTokens) { jsmFn(name, (done) => { - var finishCallback = () => { - // Wait one more event loop to make sure we catch unreturned promises and - // promise rejections. - setTimeout(done, 0); - }; - var returnedTestValue = - runInTestZone(() => testInjector.execute(testFn), finishCallback, done.fail); + var returnedTestValue; + try { + returnedTestValue = testInjector.execute(testFn); + } catch (err) { + done.fail(err); + return; + } if (testFn.isAsync) { if (_isPromiseLike(returnedTestValue)) { - (>returnedTestValue).then(null, (err) => { done.fail(err); }); + (>returnedTestValue).then(() => { done(); }, (err) => { done.fail(err); }); } else { done.fail('Error: injectAsync was expected to return a promise, but the ' + ' returned value was: ' + returnedTestValue); @@ -206,6 +152,7 @@ function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | An done.fail('Error: inject returned a value. Did you mean to use injectAsync? Returned ' + 'value was: ' + returnedTestValue); } + done(); } }, timeOut); } else { @@ -232,17 +179,17 @@ export function beforeEach(fn: FunctionWithParamTokens | AnyTestFn): void { // The test case uses inject(). ie `beforeEach(inject([ClassA], (a) => { ... // }));` jsmBeforeEach((done) => { - var finishCallback = () => { - // Wait one more event loop to make sure we catch unreturned promises and - // promise rejections. - setTimeout(done, 0); - }; - var returnedTestValue = - runInTestZone(() => testInjector.execute(fn), finishCallback, done.fail); + var returnedTestValue; + try { + returnedTestValue = testInjector.execute(fn); + } catch (err) { + done.fail(err); + return; + } if (fn.isAsync) { if (_isPromiseLike(returnedTestValue)) { - (>returnedTestValue).then(null, (err) => { done.fail(err); }); + (>returnedTestValue).then(() => { done(); }, (err) => { done.fail(err); }); } else { done.fail('Error: injectAsync was expected to return a promise, but the ' + ' returned value was: ' + returnedTestValue); @@ -252,6 +199,7 @@ export function beforeEach(fn: FunctionWithParamTokens | AnyTestFn): void { done.fail('Error: inject returned a value. Did you mean to use injectAsync? Returned ' + 'value was: ' + returnedTestValue); } + done(); } }); } else { diff --git a/modules/angular2/test/testing/static_assets/test.html b/modules/angular2/test/testing/static_assets/test.html new file mode 100644 index 0000000000..4c2b23755f --- /dev/null +++ b/modules/angular2/test/testing/static_assets/test.html @@ -0,0 +1 @@ +from external template diff --git a/modules/angular2/test/testing/testing_public_spec.ts b/modules/angular2/test/testing/testing_public_spec.ts index f37c918dcd..120ca2705c 100644 --- a/modules/angular2/test/testing/testing_public_spec.ts +++ b/modules/angular2/test/testing/testing_public_spec.ts @@ -94,6 +94,15 @@ class TestViewProvidersComp { constructor(private fancyService: FancyService) {} } +@Component({selector: 'external-template-comp'}) +@View({templateUrl: '/base/modules/angular2/test/testing/static_assets/test.html'}) +class ExternalTemplateComp { +} + +@Component({selector: 'bad-template-comp'}) +@View({templateUrl: 'non-existant.html'}) +class BadTemplateUrl { +} export function main() { describe('angular2 jasmine matchers', () => { @@ -273,11 +282,12 @@ export function main() { restoreJasmineIt(); }); - it('should fail when an asynchronous error is thrown', (done) => { + // TODO(juliemr): reenable this test when we are using a test zone and can capture this error. + xit('should fail when an asynchronous error is thrown', (done) => { var itPromise = patchJasmineIt(); it('throws an async error', - inject([], () => { setTimeout(() => { throw new Error('bar'); }, 0); })); + injectAsync([], () => { setTimeout(() => { throw new Error('bar'); }, 0); })); itPromise.then(() => { done.fail('Expected test to fail, but it did not'); }, (err) => { expect(err.message).toEqual('bar'); @@ -304,6 +314,19 @@ export function main() { restoreJasmineIt(); }); + it('should fail when an XHR fails', (done) => { + var itPromise = patchJasmineIt(); + + it('should fail with an error from a promise', + injectAsync([TestComponentBuilder], (tcb) => { return tcb.createAsync(BadTemplateUrl); })); + + itPromise.then(() => { done.fail('Expected test to fail, but it did not'); }, (err) => { + expect(err).toEqual('Failed to load non-existant.html'); + done(); + }); + restoreJasmineIt(); + }); + describe('using beforeEachProviders', () => { beforeEachProviders(() => [bind(FancyService).toValue(new FancyService())]); @@ -428,5 +451,16 @@ export function main() { .toHaveText('injected value: mocked out value'); }); })); + + it('should allow an external templateUrl', + injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => { + + return tcb.createAsync(ExternalTemplateComp) + .then((componentFixture) => { + componentFixture.detectChanges(); + expect(componentFixture.debugElement.nativeElement) + .toHaveText('from external template\n'); + }); + })); }); } diff --git a/modules_dart/angular2_testing/test/angular2_testing_test.dart b/modules_dart/angular2_testing/test/angular2_testing_test.dart index c0076eaafc..e0bfd82e77 100644 --- a/modules_dart/angular2_testing/test/angular2_testing_test.dart +++ b/modules_dart/angular2_testing/test/angular2_testing_test.dart @@ -26,6 +26,13 @@ class TestService { } } +@Component(selector: 'external-template-cmp') +@View(templateUrl: 'test_template.html') +class ExternalTemplateComponent { + ExternalTemplateComponent() { + } +} + class MyToken {} const TEMPLATE = @@ -79,6 +86,15 @@ void main() { expect(rootTC.debugElement.nativeElement.text, equals('1;2;3;')); }); + ngTest('should allow a component using a templateUrl', (TestComponentBuilder tcb) async { + var rootTC = await tcb + .createAsync(ExternalTemplateComponent); + + rootTC.detectChanges(); + + expect(rootTC.debugElement.nativeElement.text, equals('from external template\n')); + }); + group('expected failures', () { ngTest('no type in param list', (notTyped) { expect(1, equals(2)); diff --git a/modules_dart/angular2_testing/test/test_template.html b/modules_dart/angular2_testing/test/test_template.html new file mode 100644 index 0000000000..4c2b23755f --- /dev/null +++ b/modules_dart/angular2_testing/test/test_template.html @@ -0,0 +1 @@ +from external template