From c72ed991ada4bef1d822132a697e57e088a0b71f Mon Sep 17 00:00:00 2001 From: Julie Ralph Date: Wed, 20 Jan 2016 15:55:30 -0800 Subject: [PATCH] fix(testing): remove test zone for now and rely on returned promises Adds tests for public Dart and TS frameworks to make sure that components with templateUrl can be created by the TestComponentBuilder. Closes #6359 Closes #6601 --- modules/angular2/src/testing/testing.ts | 88 ++++--------------- .../test/testing/static_assets/test.html | 1 + .../test/testing/testing_public_spec.ts | 38 +++++++- .../test/angular2_testing_test.dart | 16 ++++ .../angular2_testing/test/test_template.html | 1 + 5 files changed, 72 insertions(+), 72 deletions(-) create mode 100644 modules/angular2/test/testing/static_assets/test.html create mode 100644 modules_dart/angular2_testing/test/test_template.html 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