diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index 99338410d525a..c5e9f2f92f71a 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -3827,29 +3827,65 @@ describe('animation tests', function() { }); }); - it('should throw when using an @prop binding without the animation module', () => { - @Component({template: `
`}) - class Cmp { - } - TestBed.configureTestingModule({declarations: [Cmp]}); - const comp = TestBed.createComponent(Cmp); - expect(() => comp.detectChanges()) - .toThrowError( - 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); + function syntheticPropError(name: string, nameKind: string) { + return `Unexpected synthetic ${nameKind} ${name} found. Please make sure that: + - Either \`BrowserAnimationsModule\` or \`NoopAnimationsModule\` are imported in your application. + - There is corresponding configuration for the animation named \`${ + name}\` defined in the \`animations\` field of the \`@Component\` decorator (see https://angular.io/api/core/Component#animations).`; + } + + describe('when modules are missing', () => { + it('should throw when using an @prop binding without the animation module', () => { + @Component({template: `
`}) + class Cmp { + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const comp = TestBed.createComponent(Cmp); + expect(() => comp.detectChanges()) + .toThrowError(syntheticPropError('@myAnimation', 'property')); + }); + + it('should throw when using an @prop listener without the animation module', () => { + @Component({template: `
`}) + class Cmp { + a = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + expect(() => TestBed.createComponent(Cmp)) + .toThrowError(syntheticPropError('@myAnimation.start', 'listener')); + }); }); - it('should throw when using an @prop listener without the animation module', () => { - @Component({template: `
`}) - class Cmp { - a: any; - } + describe('when modules are present, but animations are missing', () => { + it('should throw when using an @prop property, BrowserAnimationModule is imported, but there is no animation rule', + () => { + @Component({template: `
`}) + class Cmp { + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule( + {declarations: [Cmp], imports: [BrowserAnimationsModule]}); + const comp = TestBed.createComponent(Cmp); + expect(() => comp.detectChanges()) + .toThrowError(syntheticPropError('@myAnimation', 'property')); + }); - expect(() => TestBed.createComponent(Cmp)) - .toThrowError( - 'Found the synthetic listener @myAnimation.start. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); + it('should throw when using an @prop listener, BrowserAnimationModule is imported, but there is no animation rule', + () => { + @Component({template: `
`}) + class Cmp { + } + + TestBed.configureTestingModule( + {declarations: [Cmp], imports: [BrowserAnimationsModule]}); + + expect(() => TestBed.createComponent(Cmp)) + .toThrowError(syntheticPropError('@myAnimation.start', 'listener')); + }); }); }); }); diff --git a/packages/platform-browser/src/dom/dom_renderer.ts b/packages/platform-browser/src/dom/dom_renderer.ts index 02db420b5fcfa..c4669275ba0c8 100644 --- a/packages/platform-browser/src/dom/dom_renderer.ts +++ b/packages/platform-browser/src/dom/dom_renderer.ts @@ -280,8 +280,10 @@ class DefaultDomRenderer2 implements Renderer2 { const AT_CHARCODE = (() => '@'.charCodeAt(0))(); function checkNoSyntheticProp(name: string, nameKind: string) { if (name.charCodeAt(0) === AT_CHARCODE) { - throw new Error(`Found the synthetic ${nameKind} ${ - name}. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.`); + throw new Error(`Unexpected synthetic ${nameKind} ${name} found. Please make sure that: + - Either \`BrowserAnimationsModule\` or \`NoopAnimationsModule\` are imported in your application. + - There is corresponding configuration for the animation named \`${ + name}\` defined in the \`animations\` field of the \`@Component\` decorator (see https://angular.io/api/core/Component#animations).`); } } diff --git a/packages/platform-server/src/server_renderer.ts b/packages/platform-server/src/server_renderer.ts index c24b8a426a194..c1e72e5dc70c0 100644 --- a/packages/platform-server/src/server_renderer.ts +++ b/packages/platform-server/src/server_renderer.ts @@ -241,8 +241,10 @@ class DefaultServerRenderer2 implements Renderer2 { const AT_CHARCODE = '@'.charCodeAt(0); function checkNoSyntheticProp(name: string, nameKind: string) { if (name.charCodeAt(0) === AT_CHARCODE) { - throw new Error(`Found the synthetic ${nameKind} ${ - name}. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.`); + throw new Error(`Unexpected synthetic ${nameKind} ${name} found. Please make sure that: + - Either \`BrowserAnimationsModule\` or \`NoopAnimationsModule\` are imported in your application. + - There is corresponding configuration for the animation named \`${ + name}\` defined in the \`animations\` field of the \`@Component\` decorator (see https://angular.io/api/core/Component#animations).`); } }