test(ivy): enable more @angular/core tests (#27654)

PR Close #27654
This commit is contained in:
Marc Laval 2018-12-13 18:16:03 +01:00 committed by Miško Hevery
parent a433baf99a
commit 8042140742
4 changed files with 143 additions and 60 deletions

View File

@ -308,7 +308,7 @@ export function getOrCreateInjectable<T>(
try { try {
const value = bloomHash(); const value = bloomHash();
if (value == null && !(flags & InjectFlags.Optional)) { if (value == null && !(flags & InjectFlags.Optional)) {
throw new Error(`No provider for ${stringify(token)}`); throw new Error(`No provider for ${stringify(token)}!`);
} else { } else {
return value; return value;
} }

View File

@ -35,6 +35,8 @@ export function stringify(value: any): string {
if (typeof value == 'function') return value.name || value; if (typeof value == 'function') return value.name || value;
if (typeof value == 'string') return value; if (typeof value == 'string') return value;
if (value == null) return ''; if (value == null) return '';
if (typeof value == 'object' && typeof value.type == 'function')
return value.type.name || value.type;
return '' + value; return '' + value;
} }

View File

@ -10,7 +10,7 @@ import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, Compon
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing'; import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {fixmeIvy} from '@angular/private/testing'; import {fixmeIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing';
@Directive({selector: '[simpleDirective]'}) @Directive({selector: '[simpleDirective]'})
class SimpleDirective { class SimpleDirective {
@ -598,57 +598,109 @@ class TestComp {
expect(el.children[0].injector.get(NeedsAppService).service).toEqual('appService'); expect(el.children[0].injector.get(NeedsAppService).service).toEqual('appService');
}); });
fixmeIvy('unknown').it('should not instantiate a directive with cyclic dependencies', () => { obsoleteInIvy('This error is no longer generated by the compiler')
TestBed.configureTestingModule({declarations: [CycleDirective]}); .it('should not instantiate a directive with cyclic dependencies', () => {
expect(() => createComponent('<div cycleDirective></div>')) TestBed.configureTestingModule({declarations: [CycleDirective]});
.toThrowError( expect(() => createComponent('<div cycleDirective></div>'))
/Template parse errors:\nCannot instantiate cyclic dependency! CycleDirective \("\[ERROR ->\]<div cycleDirective><\/div>"\): .*TestComp.html@0:0/);
});
fixmeIvy('unknown').it(
'should not instantiate a directive in a view that has a host dependency on providers' +
' of the component',
() => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsServiceFromHost]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent></div>'))
.toThrowError( .toThrowError(
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/); /Template parse errors:\nCannot instantiate cyclic dependency! CycleDirective \("\[ERROR ->\]<div cycleDirective><\/div>"\): .*TestComp.html@0:0/);
}); });
fixmeIvy('unknown').it( onlyInIvy('This error is generated by the runtime of Ivy')
'should not instantiate a directive in a view that has a host dependency on providers' + .it('should not instantiate a directive with cyclic dependencies', () => {
' of a decorator directive', TestBed.configureTestingModule({declarations: [CycleDirective]});
() => { expect(() => createComponent('<div cycleDirective></div>'))
TestBed.configureTestingModule( .toThrowError('Circular dep for CycleDirective');
{declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent someOtherDirective></div>'))
.toThrowError(
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/);
}); });
fixmeIvy('unknown').it( obsoleteInIvy('This error is no longer generated by the compiler')
'should not instantiate a directive in a view that has a self dependency on a parent directive', .it('should not instantiate a directive in a view that has a host dependency on providers' +
() => { ' of the component',
TestBed.configureTestingModule( () => {
{declarations: [SimpleDirective, NeedsDirectiveFromSelf]}); TestBed.configureTestingModule(
expect( {declarations: [SimpleComponent, NeedsServiceFromHost]});
() => createComponent( TestBed.overrideComponent(
'<div simpleDirective><div needsDirectiveFromSelf></div></div>')) SimpleComponent,
.toThrowError( {set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
/Template parse errors:\nNo provider for SimpleDirective \("<div simpleDirective>\[ERROR ->\]<div needsDirectiveFromSelf><\/div><\/div>"\): .*TestComp.html@0:21/); TestBed.overrideComponent(
}); SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent></div>'))
.toThrowError(
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/);
});
onlyInIvy('This error is generated by the runtime of Ivy')
.it('should not instantiate a directive in a view that has a host dependency on providers' +
' of the component',
() => {
TestBed.configureTestingModule(
{declarations: [SimpleComponent, NeedsServiceFromHost]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent></div>'))
.toThrowError('NodeInjector: NOT_FOUND [service]');
});
obsoleteInIvy('This error is no longer generated by the compiler')
.it('should not instantiate a directive in a view that has a host dependency on providers' +
' of a decorator directive',
() => {
TestBed.configureTestingModule(
{declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent someOtherDirective></div>'))
.toThrowError(
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/);
});
onlyInIvy('This error is generated by the runtime of Ivy')
.it('should not instantiate a directive in a view that has a host dependency on providers' +
' of a decorator directive',
() => {
TestBed.configureTestingModule(
{declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]});
TestBed.overrideComponent(
SimpleComponent,
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
expect(() => createComponent('<div simpleComponent someOtherDirective></div>'))
.toThrowError('NodeInjector: NOT_FOUND [service]');
});
obsoleteInIvy('This error is no longer generated by the compiler')
.it('should not instantiate a directive in a view that has a self dependency on a parent directive',
() => {
TestBed.configureTestingModule(
{declarations: [SimpleDirective, NeedsDirectiveFromSelf]});
expect(
() => createComponent(
'<div simpleDirective><div needsDirectiveFromSelf></div></div>'))
.toThrowError(
/Template parse errors:\nNo provider for SimpleDirective \("<div simpleDirective>\[ERROR ->\]<div needsDirectiveFromSelf><\/div><\/div>"\): .*TestComp.html@0:21/);
});
onlyInIvy('This error is generated by the runtime of Ivy')
.it('should not instantiate a directive in a view that has a self dependency on a parent directive',
() => {
TestBed.configureTestingModule(
{declarations: [SimpleDirective, NeedsDirectiveFromSelf]});
expect(
() => createComponent(
'<div simpleDirective><div needsDirectiveFromSelf></div></div>'))
.toThrowError('NodeInjector: NOT_FOUND [SimpleDirective]');
});
it('should instantiate directives that depend on other directives', fakeAsync(() => { it('should instantiate directives that depend on other directives', fakeAsync(() => {
TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]}); TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]});
@ -691,17 +743,28 @@ class TestComp {
expect(el.componentInstance.service).toEqual('appService'); expect(el.componentInstance.service).toEqual('appService');
}); });
fixmeIvy('unknown').it( obsoleteInIvy('This error is no longer generated by the compiler')
'should not instantiate directives that depend on other directives on the host element', .it('should not instantiate directives that depend on other directives on the host element',
() => { () => {
TestBed.configureTestingModule( TestBed.configureTestingModule(
{declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]}); {declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]});
TestBed.overrideComponent( TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsDirectiveFromHost></div>'}}); SimpleComponent, {set: {template: '<div needsDirectiveFromHost></div>'}});
expect(() => createComponent('<div simpleComponent simpleDirective></div>')) expect(() => createComponent('<div simpleComponent simpleDirective></div>'))
.toThrowError( .toThrowError(
/Template parse errors:\nNo provider for SimpleDirective \("\[ERROR ->\]<div needsDirectiveFromHost><\/div>"\): .*SimpleComponent.html@0:0/); /Template parse errors:\nNo provider for SimpleDirective \("\[ERROR ->\]<div needsDirectiveFromHost><\/div>"\): .*SimpleComponent.html@0:0/);
}); });
onlyInIvy('This error is generated by the runtime of Ivy')
.it('should not instantiate directives that depend on other directives on the host element',
() => {
TestBed.configureTestingModule(
{declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsDirectiveFromHost></div>'}});
expect(() => createComponent('<div simpleComponent simpleDirective></div>'))
.toThrowError('NodeInjector: NOT_FOUND [SimpleDirective]');
});
fixmeIvy('unknown').it( fixmeIvy('unknown').it(
'should allow to use the NgModule injector from a root ViewContainerRef.parentInjector', 'should allow to use the NgModule injector from a root ViewContainerRef.parentInjector',
@ -884,7 +947,7 @@ class TestComp {
.toEqual(el.childNodes[0].injector.get(NeedsViewContainerRef).viewContainer.element); .toEqual(el.childNodes[0].injector.get(NeedsViewContainerRef).viewContainer.element);
}); });
fixmeIvy('unknown').it('should throw if there is no TemplateRef', () => { it('should throw if there is no TemplateRef', () => {
TestBed.configureTestingModule({declarations: [NeedsTemplateRef]}); TestBed.configureTestingModule({declarations: [NeedsTemplateRef]});
expect(() => createComponent('<div needsTemplateRef></div>')) expect(() => createComponent('<div needsTemplateRef></div>'))
.toThrowError(/No provider for TemplateRef!/); .toThrowError(/No provider for TemplateRef!/);

View File

@ -79,6 +79,24 @@ export function obsoleteInIvy(reason: string): JasmineMethods {
return ivyEnabled ? IGNORE : PASSTHROUGH; return ivyEnabled ? IGNORE : PASSTHROUGH;
} }
/**
* A function to conditionally skip the execution of tests that are not relevant when
* not running against Ivy.
*
* ```
* onlyInIvy('some reason').describe(...);
* ```
*
* or
*
* ```
* onlyInIvy('some reason').it(...);
* ```
*/
export function onlyInIvy(reason: string): JasmineMethods {
return ivyEnabled ? PASSTHROUGH : IGNORE;
}
/** /**
* A function to conditionally skip the execution of tests that have intentionally * A function to conditionally skip the execution of tests that have intentionally
* been broken when running against Ivy. * been broken when running against Ivy.