Revert "fix(core): log error instead of warning for unknown properties and elements (#35798)" (#35845)

This reverts commit 00f3c58bb9.
Rolling back because it could be breaking e2e tests that assert that
there are no errors in the console after the assertions have run. We can
re-add this in v10.

PR Close #35845
This commit is contained in:
Andrew Scott 2020-03-03 14:58:53 -08:00 committed by atscott
parent 00f3c58bb9
commit d543b13e5c
7 changed files with 47 additions and 47 deletions

View File

@ -36,7 +36,7 @@ function elementStartFirstCreatePass(
const hasDirectives = const hasDirectives =
resolveDirectives(tView, lView, tNode, getConstant<string[]>(tViewConsts, localRefsIndex)); resolveDirectives(tView, lView, tNode, getConstant<string[]>(tViewConsts, localRefsIndex));
ngDevMode && logUnknownElementError(tView, lView, native, tNode, hasDirectives); ngDevMode && warnAboutUnknownElement(tView, lView, native, tNode, hasDirectives);
if (tNode.mergedAttrs !== null) { if (tNode.mergedAttrs !== null) {
computeStaticStyling(tNode, tNode.mergedAttrs); computeStaticStyling(tNode, tNode.mergedAttrs);
@ -171,7 +171,7 @@ export function ɵɵelement(
ɵɵelementEnd(); ɵɵelementEnd();
} }
function logUnknownElementError( function warnAboutUnknownElement(
tView: TView, lView: LView, element: RElement, tNode: TNode, hasDirectives: boolean): void { tView: TView, lView: LView, element: RElement, tNode: TNode, hasDirectives: boolean): void {
const schemas = tView.schemas; const schemas = tView.schemas;
@ -197,17 +197,17 @@ function logUnknownElementError(
!customElements.get(tagName)); !customElements.get(tagName));
if (isUnknown && !matchingSchemas(tView, lView, tagName)) { if (isUnknown && !matchingSchemas(tView, lView, tagName)) {
let message = `'${tagName}' is not a known element:\n`; let warning = `'${tagName}' is not a known element:\n`;
message += warning +=
`1. If '${tagName}' is an Angular component, then verify that it is part of this module.\n`; `1. If '${tagName}' is an Angular component, then verify that it is part of this module.\n`;
if (tagName && tagName.indexOf('-') > -1) { if (tagName && tagName.indexOf('-') > -1) {
message += warning +=
`2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`; `2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`;
} else { } else {
message += warning +=
`2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`;
} }
console.error(message); console.warn(warning);
} }
} }
} }

View File

@ -962,7 +962,7 @@ export function elementPropertyInternal<T>(
validateAgainstEventProperties(propName); validateAgainstEventProperties(propName);
if (!validateProperty(tView, lView, element, propName, tNode)) { if (!validateProperty(tView, lView, element, propName, tNode)) {
// Return here since we only log warnings for unknown properties. // Return here since we only log warnings for unknown properties.
logUnknownPropertyError(propName, tNode); warnAboutUnknownProperty(propName, tNode);
return; return;
} }
ngDevMode.rendererSetProperty++; ngDevMode.rendererSetProperty++;
@ -982,7 +982,7 @@ export function elementPropertyInternal<T>(
// If the node is a container and the property didn't // If the node is a container and the property didn't
// match any of the inputs or schemas we should throw. // match any of the inputs or schemas we should throw.
if (ngDevMode && !matchingSchemas(tView, lView, tNode.tagName)) { if (ngDevMode && !matchingSchemas(tView, lView, tNode.tagName)) {
logUnknownPropertyError(propName, tNode); warnAboutUnknownProperty(propName, tNode);
} }
} }
} }
@ -1070,12 +1070,12 @@ export function matchingSchemas(tView: TView, lView: LView, tagName: string | nu
} }
/** /**
* Logs an error that a property is not supported on an element. * Logs a warning that a property is not supported on an element.
* @param propName Name of the invalid property. * @param propName Name of the invalid property.
* @param tNode Node on which we encountered the property. * @param tNode Node on which we encountered the property.
*/ */
function logUnknownPropertyError(propName: string, tNode: TNode): void { function warnAboutUnknownProperty(propName: string, tNode: TNode): void {
console.error( console.warn(
`Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`); `Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`);
} }

View File

@ -97,7 +97,7 @@ describe('NgModule', () => {
}); });
describe('schemas', () => { describe('schemas', () => {
onlyInIvy('Unknown property logs an error message instead of throwing') onlyInIvy('Unknown property warning logged instead of throwing an error')
.it('should throw on unknown props if NO_ERRORS_SCHEMA is absent', () => { .it('should throw on unknown props if NO_ERRORS_SCHEMA is absent', () => {
@Component({ @Component({
selector: 'my-comp', selector: 'my-comp',
@ -120,7 +120,7 @@ describe('NgModule', () => {
TestBed.configureTestingModule({imports: [MyModule]}); TestBed.configureTestingModule({imports: [MyModule]});
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges(); fixture.detectChanges();
expect(spy.calls.mostRecent().args[0]) expect(spy.calls.mostRecent().args[0])
@ -185,15 +185,15 @@ describe('NgModule', () => {
}).not.toThrow(); }).not.toThrow();
}); });
onlyInIvy('unknown element check logs an error message rather than throwing') onlyInIvy('unknown element check logs a warning rather than throwing')
.it('should log an error about unknown element without CUSTOM_ELEMENTS_SCHEMA for element with dash in tag name', .it('should warn about unknown element without CUSTOM_ELEMENTS_SCHEMA for element with dash in tag name',
() => { () => {
@Component({template: `<custom-el></custom-el>`}) @Component({template: `<custom-el></custom-el>`})
class MyComp { class MyComp {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
TestBed.configureTestingModule({declarations: [MyComp]}); TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges(); fixture.detectChanges();
@ -215,14 +215,14 @@ describe('NgModule', () => {
}).toThrowError(/'custom-el' is not a known element/); }).toThrowError(/'custom-el' is not a known element/);
}); });
onlyInIvy('unknown element check logs an error message rather than throwing') onlyInIvy('unknown element check logs a warning rather than throwing')
.it('should log an error about unknown element without CUSTOM_ELEMENTS_SCHEMA for element without dash in tag name', .it('should warn about unknown element without CUSTOM_ELEMENTS_SCHEMA for element without dash in tag name',
() => { () => {
@Component({template: `<custom></custom>`}) @Component({template: `<custom></custom>`})
class MyComp { class MyComp {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
TestBed.configureTestingModule({declarations: [MyComp]}); TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges(); fixture.detectChanges();
@ -245,8 +245,8 @@ describe('NgModule', () => {
}); });
onlyInIvy('test relies on Ivy-specific AOT format') onlyInIvy('test relies on Ivy-specific AOT format')
.it('should not log unknown element error for AOT-compiled components', () => { .it('should not log unknown element warning for AOT-compiled components', () => {
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
/* /*
* @Component({ * @Component({
@ -310,13 +310,13 @@ describe('NgModule', () => {
expect(spy).not.toHaveBeenCalled(); expect(spy).not.toHaveBeenCalled();
}); });
onlyInIvy('unknown element check logs an error message rather than throwing') onlyInIvy('unknown element check logs a warning rather than throwing')
.it('should not log an error about unknown elements with CUSTOM_ELEMENTS_SCHEMA', () => { .it('should not warn about unknown elements with CUSTOM_ELEMENTS_SCHEMA', () => {
@Component({template: `<custom-el></custom-el>`}) @Component({template: `<custom-el></custom-el>`})
class MyComp { class MyComp {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [MyComp], declarations: [MyComp],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
@ -344,13 +344,13 @@ describe('NgModule', () => {
}).not.toThrow(); }).not.toThrow();
}); });
onlyInIvy('unknown element check logs an error message rather than throwing') onlyInIvy('unknown element check logs a warning rather than throwing')
.it('should not log an error about unknown elements with NO_ERRORS_SCHEMA', () => { .it('should not warn about unknown elements with NO_ERRORS_SCHEMA', () => {
@Component({template: `<custom-el></custom-el>`}) @Component({template: `<custom-el></custom-el>`})
class MyComp { class MyComp {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [MyComp], declarations: [MyComp],
schemas: [NO_ERRORS_SCHEMA], schemas: [NO_ERRORS_SCHEMA],
@ -378,8 +378,8 @@ describe('NgModule', () => {
}).not.toThrow(); }).not.toThrow();
}); });
onlyInIvy('unknown element check logs an error message rather than throwing') onlyInIvy('unknown element check logs a warning rather than throwing')
.it('should not log an error about unknown elements if element matches a directive', () => { .it('should not warn about unknown elements if element matches a directive', () => {
@Component({ @Component({
selector: 'custom-el', selector: 'custom-el',
template: '', template: '',
@ -391,7 +391,7 @@ describe('NgModule', () => {
class MyComp { class MyComp {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
TestBed.configureTestingModule({declarations: [MyComp, CustomEl]}); TestBed.configureTestingModule({declarations: [MyComp, CustomEl]});
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);
@ -420,8 +420,8 @@ describe('NgModule', () => {
}).not.toThrow(); }).not.toThrow();
}); });
onlyInIvy('unknown element check logs an error message rather than throwing') onlyInIvy('unknown element check logs a warning rather than throwing')
.it('should not log an error for HTML elements inside an SVG foreignObject', () => { .it('should not warn for HTML elements inside an SVG foreignObject', () => {
@Component({ @Component({
template: ` template: `
<svg> <svg>
@ -438,7 +438,7 @@ describe('NgModule', () => {
class MyModule { class MyModule {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
TestBed.configureTestingModule({imports: [MyModule]}); TestBed.configureTestingModule({imports: [MyModule]});
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);

View File

@ -1632,7 +1632,7 @@ function declareTests(config?: {useJit: boolean}) {
}); });
describe('Property bindings', () => { describe('Property bindings', () => {
modifiedInIvy('Unknown property error throws an error instead of logging it') modifiedInIvy('Unknown property error throws an error instead of logging a warning')
.it('should throw on bindings to unknown properties', () => { .it('should throw on bindings to unknown properties', () => {
TestBed.configureTestingModule({declarations: [MyComp]}); TestBed.configureTestingModule({declarations: [MyComp]});
const template = '<div unknown="{{ctxProp}}"></div>'; const template = '<div unknown="{{ctxProp}}"></div>';
@ -1646,20 +1646,20 @@ function declareTests(config?: {useJit: boolean}) {
} }
}); });
onlyInIvy('Unknown property logs an error message instead of throwing') onlyInIvy('Unknown property warning logged instead of throwing an error')
.it('should throw on bindings to unknown properties', () => { .it('should throw on bindings to unknown properties', () => {
TestBed.configureTestingModule({declarations: [MyComp]}); TestBed.configureTestingModule({declarations: [MyComp]});
const template = '<div unknown="{{ctxProp}}"></div>'; const template = '<div unknown="{{ctxProp}}"></div>';
TestBed.overrideComponent(MyComp, {set: {template}}); TestBed.overrideComponent(MyComp, {set: {template}});
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges(); fixture.detectChanges();
expect(spy.calls.mostRecent().args[0]) expect(spy.calls.mostRecent().args[0])
.toMatch(/Can't bind to 'unknown' since it isn't a known property of 'div'./); .toMatch(/Can't bind to 'unknown' since it isn't a known property of 'div'./);
}); });
modifiedInIvy('Unknown property error thrown instead of logging it') modifiedInIvy('Unknown property error thrown instead of a warning')
.it('should throw on bindings to unknown properties', () => { .it('should throw on bindings to unknown properties', () => {
TestBed.configureTestingModule({imports: [CommonModule], declarations: [MyComp]}); TestBed.configureTestingModule({imports: [CommonModule], declarations: [MyComp]});
const template = '<div *ngFor="let item in ctxArrProp">{{item}}</div>'; const template = '<div *ngFor="let item in ctxArrProp">{{item}}</div>';
@ -1675,12 +1675,12 @@ function declareTests(config?: {useJit: boolean}) {
} }
}); });
onlyInIvy('Unknown property logs an error message instead of throwing it') onlyInIvy('Unknown property logs a warning instead of throwing an error')
.it('should throw on bindings to unknown properties', () => { .it('should throw on bindings to unknown properties', () => {
TestBed.configureTestingModule({imports: [CommonModule], declarations: [MyComp]}); TestBed.configureTestingModule({imports: [CommonModule], declarations: [MyComp]});
const template = '<div *ngFor="let item in ctxArrProp">{{item}}</div>'; const template = '<div *ngFor="let item in ctxArrProp">{{item}}</div>';
TestBed.overrideComponent(MyComp, {set: {template}}); TestBed.overrideComponent(MyComp, {set: {template}});
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges(); fixture.detectChanges();
expect(spy.calls.mostRecent().args[0]) expect(spy.calls.mostRecent().args[0])

View File

@ -250,7 +250,7 @@ function declareTests(config?: {useJit: boolean}) {
expect(() => createModule(SomeModule)).toThrowError(/Can't bind to 'someUnknownProp'/); expect(() => createModule(SomeModule)).toThrowError(/Can't bind to 'someUnknownProp'/);
}); });
onlyInIvy('Unknown property error logged, instead of throwing') onlyInIvy('Unknown property warning logged, instead of throwing an error')
.it('should error on unknown bound properties on custom elements by default', () => { .it('should error on unknown bound properties on custom elements by default', () => {
@Component({template: '<div [someUnknownProp]="true"></div>'}) @Component({template: '<div [someUnknownProp]="true"></div>'})
class ComponentUsingInvalidProperty { class ComponentUsingInvalidProperty {
@ -260,7 +260,7 @@ function declareTests(config?: {useJit: boolean}) {
class SomeModule { class SomeModule {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
const fixture = createComp(ComponentUsingInvalidProperty, SomeModule); const fixture = createComp(ComponentUsingInvalidProperty, SomeModule);
fixture.detectChanges(); fixture.detectChanges();
expect(spy.calls.mostRecent().args[0]).toMatch(/Can't bind to 'someUnknownProp'/); expect(spy.calls.mostRecent().args[0]).toMatch(/Can't bind to 'someUnknownProp'/);

View File

@ -263,12 +263,12 @@ function declareTests(config?: {useJit: boolean}) {
.toThrowError(/Can't bind to 'xlink:href'/); .toThrowError(/Can't bind to 'xlink:href'/);
}); });
onlyInIvy('Unknown property logs an error message instead of throwing') onlyInIvy('Unknown property warning logged instead of throwing an error')
.it('should escape unsafe SVG attributes', () => { .it('should escape unsafe SVG attributes', () => {
const template = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`; const template = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`;
TestBed.overrideComponent(SecuredComponent, {set: {template}}); TestBed.overrideComponent(SecuredComponent, {set: {template}});
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
const fixture = TestBed.createComponent(SecuredComponent); const fixture = TestBed.createComponent(SecuredComponent);
fixture.detectChanges(); fixture.detectChanges();
expect(spy.calls.mostRecent().args[0]).toMatch(/Can't bind to 'xlink:href'/); expect(spy.calls.mostRecent().args[0]).toMatch(/Can't bind to 'xlink:href'/);

View File

@ -937,7 +937,7 @@ Did you run and wait for 'resolveComponentResources()'?` :
}); });
modifiedInIvy(`Unknown property error thrown instead of logging a message`) modifiedInIvy(`Unknown property error thrown instead of logging a warning`)
.it('should error on unknown bound properties on custom elements by default', () => { .it('should error on unknown bound properties on custom elements by default', () => {
@Component({template: '<some-element [someUnknownProp]="true"></some-element>'}) @Component({template: '<some-element [someUnknownProp]="true"></some-element>'})
class ComponentUsingInvalidProperty { class ComponentUsingInvalidProperty {
@ -956,13 +956,13 @@ Did you run and wait for 'resolveComponentResources()'?` :
restoreJasmineIt(); restoreJasmineIt();
}); });
onlyInIvy(`Unknown property error logged instead of throwing`) onlyInIvy(`Unknown property warning logged instead of an error`)
.it('should error on unknown bound properties on custom elements by default', () => { .it('should error on unknown bound properties on custom elements by default', () => {
@Component({template: '<div [someUnknownProp]="true"></div>'}) @Component({template: '<div [someUnknownProp]="true"></div>'})
class ComponentUsingInvalidProperty { class ComponentUsingInvalidProperty {
} }
const spy = spyOn(console, 'error'); const spy = spyOn(console, 'warn');
withModule({declarations: [ComponentUsingInvalidProperty]}, () => { withModule({declarations: [ComponentUsingInvalidProperty]}, () => {
const fixture = TestBed.createComponent(ComponentUsingInvalidProperty); const fixture = TestBed.createComponent(ComponentUsingInvalidProperty);
fixture.detectChanges(); fixture.detectChanges();