From 32ae84da28ea8722fa17dd289f0134223ac903dd Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 21 Feb 2019 00:00:02 +0100 Subject: [PATCH] fixup! fix(ivy): incorrectly remapping certain properties that refer to inputs (#28765) PR Close #28765 --- .../r3_view_compiler_binding_spec.ts | 42 ++++++++ .../core/test/acceptance/properties_spec.ts | 63 +++++++++++ packages/core/test/render3/properties_spec.ts | 64 ----------- .../angular_material_test_blocklist.js | 100 +----------------- 4 files changed, 109 insertions(+), 160 deletions(-) create mode 100644 packages/core/test/acceptance/properties_spec.ts diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts index ef78ee8caa..bc4c880ec8 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts @@ -137,6 +137,48 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); expect(result.source).not.toContain('i0.ɵelementProperty'); }); + + it('should not remap property names whose names do not correspond to their attribute names', + () => { + const files = { + app: { + 'spec.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-component', + template: \` + \` + }) + export class MyComponent { + forValue = 'some-input'; + } + + @NgModule({declarations: [MyComponent]}) + export class MyModule {} + ` + } + }; + + const template = ` + const $c0$ = [${AttributeMarker.SelectOnly}, "for"]; + + // ... + + function MyComponent_Template(rf, ctx) { + if (rf & 1) { + $i0$.ɵelement(0, "label", _c0); + } + if (rf & 2) { + $i0$.ɵelementProperty(0, "for", $i0$.ɵbind(ctx.forValue)); + } + }`; + + const result = compile(files, angularFiles); + + expectEmit(result.source, template, 'Incorrect template'); + }); + }); describe('host bindings', () => { diff --git a/packages/core/test/acceptance/properties_spec.ts b/packages/core/test/acceptance/properties_spec.ts new file mode 100644 index 0000000000..d8e591d265 --- /dev/null +++ b/packages/core/test/acceptance/properties_spec.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Input} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {By} from '@angular/platform-browser'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; + +describe('elementProperty', () => { + it('should bind to properties whose names do not correspond to their attribute names', () => { + @Component({template: ''}) + class MyComp { + forValue?: string; + } + + TestBed.configureTestingModule({declarations: [MyComp]}); + const fixture = TestBed.createComponent(MyComp); + const labelNode = fixture.debugElement.query(By.css('label')); + + fixture.componentInstance.forValue = 'some-input'; + fixture.detectChanges(); + + expect(labelNode.nativeElement.getAttribute('for')).toBe('some-input'); + + fixture.componentInstance.forValue = 'some-textarea'; + fixture.detectChanges(); + + expect(labelNode.nativeElement.getAttribute('for')).toBe('some-textarea'); + }); + + it('should not map properties whose names do not correspond to their attribute names, ' + + 'if they correspond to inputs', + () => { + + @Component({template: '', selector: 'my-comp'}) + class MyComp { + @Input() for !:string; + } + + @Component({template: ''}) + class App { + forValue?: string; + } + + TestBed.configureTestingModule({declarations: [App, MyComp]}); + const fixture = TestBed.createComponent(App); + const myCompNode = fixture.debugElement.query(By.directive(MyComp)); + fixture.componentInstance.forValue = 'hello'; + fixture.detectChanges(); + expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy(); + expect(myCompNode.componentInstance.for).toBe('hello'); + + fixture.componentInstance.forValue = 'hej'; + fixture.detectChanges(); + expect(myCompNode.nativeElement.getAttribute('for')).toBeFalsy(); + expect(myCompNode.componentInstance.for).toBe('hej'); + }); +}); diff --git a/packages/core/test/render3/properties_spec.ts b/packages/core/test/render3/properties_spec.ts index 1a9239a423..f7bb2f2ac8 100644 --- a/packages/core/test/render3/properties_spec.ts +++ b/packages/core/test/render3/properties_spec.ts @@ -76,26 +76,6 @@ describe('elementProperty', () => { expect(fixture.html).toEqual(''); }); - it('should map properties whose names do not correspond to their attribute names', () => { - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'label'); - } - if (rf & RenderFlags.Update) { - elementProperty(0, 'for', bind(ctx.forValue)); - } - }, 1, 1); - - const fixture = new ComponentFixture(App); - fixture.component.forValue = 'some-input'; - fixture.update(); - expect(fixture.html).toEqual(''); - - fixture.component.forValue = 'some-textarea'; - fixture.update(); - expect(fixture.html).toEqual(''); - }); - describe('input properties', () => { let button: MyButton; let otherDir: OtherDir; @@ -384,50 +364,6 @@ describe('elementProperty', () => { expect(otherDir !.id).toEqual(3); }); - it('should not map properties whose names do not correspond to their attribute names, ' + - 'if they correspond to inputs', - () => { - let comp: Comp; - - class Comp { - // TODO(issue/24571): remove '!'. - // clang-format off - for !: string; - // clang-format on - - static ngComponentDef = defineComponent({ - type: Comp, - selectors: [['comp']], - consts: 0, - vars: 0, - template: function(rf: RenderFlags, ctx: any) {}, - factory: () => comp = new Comp(), - inputs: {for: 'for'} - }); - } - - /** */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'comp'); - } - if (rf & RenderFlags.Update) { - elementProperty(0, 'for', bind(ctx.forValue)); - } - }, 1, 1, [Comp]); - - const fixture = new ComponentFixture(App); - fixture.component.forValue = 'hello'; - fixture.update(); - expect(fixture.html).toEqual(``); - expect(comp !.for).toEqual('hello'); - - fixture.component.forValue = 'hej'; - fixture.update(); - expect(fixture.html).toEqual(``); - expect(comp !.for).toEqual('hej'); - }); - }); describe('attributes and input properties', () => { diff --git a/tools/material-ci/angular_material_test_blocklist.js b/tools/material-ci/angular_material_test_blocklist.js index 2fba4b40c8..fe95155b05 100644 --- a/tools/material-ci/angular_material_test_blocklist.js +++ b/tools/material-ci/angular_material_test_blocklist.js @@ -733,73 +733,9 @@ window.testBlocklist = { "error": "Error: Expected null not to be null.", "notes": "Unknown" }, - "MatDatepicker with MatNativeDateModule datepicker with formControl should update datepicker when formControl changes": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with formControl should update formControl when date is selected": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with formControl should disable input when form control disabled": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with formControl should disable toggle when form control disabled": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should set `aria-haspopup` on the toggle button": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should open calendar when toggle clicked": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should not open calendar when toggle clicked if datepicker is disabled": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should not open calendar when toggle clicked if input is disabled": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should set the `button` type on the trigger to prevent form submissions": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should remove the underlying SVG icon from the tab order": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should restore focus to the toggle after the calendar is closed": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should re-render when the i18n labels change": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, "MatDatepicker with MatNativeDateModule datepicker with mat-datepicker-toggle should toggle the active state of the datepicker toggle": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with custom mat-datepicker-toggle icon should be able to override the mat-datepicker-toggle icon": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with tabindex on mat-datepicker-toggle should forward the tabindex to the underlying button": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with tabindex on mat-datepicker-toggle should clear the tabindex from the mat-datepicker-toggle host": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with tabindex on mat-datepicker-toggle should forward focus to the underlying button when the host is focused": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" + "error": "Error: this._portalOutlet is undefined.", + "notes": "FW-1019: Design new API to replace static queries" }, "MatDatepicker with MatNativeDateModule datepicker inside mat-form-field should pass the form field theme color to the overlay": { "error": "TypeError: Cannot read property 'classList' of null", @@ -809,37 +745,9 @@ window.testBlocklist = { "error": "TypeError: Cannot read property 'classList' of null", "notes": "Unknown" }, - "MatDatepicker with MatNativeDateModule datepicker with min and max dates and validation should use min and max dates specified by the input": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with min and max dates and validation should mark invalid when value is before min": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with min and max dates and validation should mark invalid when value is after max": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with min and max dates and validation should not mark invalid when value equals min": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with min and max dates and validation should not mark invalid when value equals max": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with min and max dates and validation should not mark invalid when value is between min and max": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, - "MatDatepicker with MatNativeDateModule datepicker with filter and validation should mark input invalid": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" - }, "MatDatepicker with MatNativeDateModule datepicker with filter and validation should disable filtered calendar cells": { - "error": "Error: Template error: Can't bind to 'htmlFor' since it isn't a known property of 'mat-datepicker-toggle'.", - "notes": "Unknown" + "error": "Error: this._portalOutlet is undefined.", + "notes": "FW-1019: Design new API to replace static queries" }, "MatDialog should set the proper animation states": { "error": "TypeError: Cannot read property 'componentInstance' of null",