fix(ivy): move views that are already attached in insert() (#29047)
Currently if a user accidentally calls ViewContainerRef.insert() with a view that has already been attached, we do not clean up the references properly, so we create a view tree with a cycle. This causes an infinite loop when the view is destroyed. This PR ensures that we fall back to ViewContainerRef.move() behavior if we try to insert a view that is already attached. This fixes the cycle and honors the user intention. PR Close #29047
This commit is contained in:
parent
ff8e4dddb2
commit
7ac58bec8a
|
@ -47,7 +47,7 @@ import {ANIMATION_PROP_PREFIX, allocateDirectiveIntoContext, createEmptyStylingC
|
||||||
import {NO_CHANGE} from './tokens';
|
import {NO_CHANGE} from './tokens';
|
||||||
import {INTERPOLATION_DELIMITER, renderStringify} from './util/misc_utils';
|
import {INTERPOLATION_DELIMITER, renderStringify} from './util/misc_utils';
|
||||||
import {findComponentView, getLViewParent, getRootContext, getRootView} from './util/view_traversal_utils';
|
import {findComponentView, getLViewParent, getRootContext, getRootView} from './util/view_traversal_utils';
|
||||||
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, loadInternal, readPatchedLView, unwrapRNode} from './util/view_utils';
|
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, loadInternal, readPatchedLView, unwrapRNode, viewAttachedToChangeDetector} from './util/view_utils';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2531,7 +2531,8 @@ export function componentRefresh<T>(adjustedElementIndex: number): void {
|
||||||
ngDevMode && assertNodeType(lView[TVIEW].data[adjustedElementIndex] as TNode, TNodeType.Element);
|
ngDevMode && assertNodeType(lView[TVIEW].data[adjustedElementIndex] as TNode, TNodeType.Element);
|
||||||
|
|
||||||
// Only attached CheckAlways components or attached, dirty OnPush components should be checked
|
// Only attached CheckAlways components or attached, dirty OnPush components should be checked
|
||||||
if (viewAttached(hostView) && hostView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
|
if (viewAttachedToChangeDetector(hostView) &&
|
||||||
|
hostView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
|
||||||
syncViewWithBlueprint(hostView);
|
syncViewWithBlueprint(hostView);
|
||||||
checkView(hostView, hostView[CONTEXT]);
|
checkView(hostView, hostView[CONTEXT]);
|
||||||
}
|
}
|
||||||
|
@ -2570,11 +2571,6 @@ function syncViewWithBlueprint(componentView: LView) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a boolean for whether the view is attached */
|
|
||||||
export function viewAttached(view: LView): boolean {
|
|
||||||
return (view[FLAGS] & LViewFlags.Attached) === LViewFlags.Attached;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instruction to distribute projectable nodes among <ng-content> occurrences in a given template.
|
* Instruction to distribute projectable nodes among <ng-content> occurrences in a given template.
|
||||||
* It takes all the selectors from the entire component's template and decides where
|
* It takes all the selectors from the entire component's template and decides where
|
||||||
|
|
|
@ -354,6 +354,7 @@ export function detachView(lContainer: LContainer, removeIndex: number): LView {
|
||||||
viewToDetach[QUERIES] !.removeView();
|
viewToDetach[QUERIES] !.removeView();
|
||||||
}
|
}
|
||||||
viewToDetach[PARENT] = null;
|
viewToDetach[PARENT] = null;
|
||||||
|
viewToDetach[NEXT] = null;
|
||||||
// Unsets the attached flag
|
// Unsets the attached flag
|
||||||
viewToDetach[FLAGS] &= ~LViewFlags.Attached;
|
viewToDetach[FLAGS] &= ~LViewFlags.Attached;
|
||||||
return viewToDetach;
|
return viewToDetach;
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {ComponentDef, DirectiveDef} from '../interfaces/definition';
|
||||||
import {TNode, TNodeFlags} from '../interfaces/node';
|
import {TNode, TNodeFlags} from '../interfaces/node';
|
||||||
import {RNode} from '../interfaces/renderer';
|
import {RNode} from '../interfaces/renderer';
|
||||||
import {StylingContext} from '../interfaces/styling';
|
import {StylingContext} from '../interfaces/styling';
|
||||||
import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TData, TVIEW} from '../interfaces/view';
|
import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, TData, TVIEW} from '../interfaces/view';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,3 +182,18 @@ export function readPatchedLView(target: any): LView|null {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a boolean for whether the view is attached to the change detection tree.
|
||||||
|
*
|
||||||
|
* Note: This determines whether a view should be checked, not whether it's inserted
|
||||||
|
* into a container. For that, you'll want `viewAttachedToContainer` below.
|
||||||
|
*/
|
||||||
|
export function viewAttachedToChangeDetector(view: LView): boolean {
|
||||||
|
return (view[FLAGS] & LViewFlags.Attached) === LViewFlags.Attached;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a boolean for whether the view is attached to a container. */
|
||||||
|
export function viewAttachedToContainer(view: LView): boolean {
|
||||||
|
return isLContainer(view[PARENT]);
|
||||||
|
}
|
||||||
|
|
|
@ -22,14 +22,14 @@ import {addToViewTree, createEmbeddedViewAndNode, createLContainer, renderEmbedd
|
||||||
import {ACTIVE_INDEX, LContainer, NATIVE, VIEWS} from './interfaces/container';
|
import {ACTIVE_INDEX, LContainer, NATIVE, VIEWS} from './interfaces/container';
|
||||||
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
|
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
|
||||||
import {RComment, RElement, isProceduralRenderer} from './interfaces/renderer';
|
import {RComment, RElement, isProceduralRenderer} from './interfaces/renderer';
|
||||||
import {CONTEXT, LView, QUERIES, RENDERER, TView, T_HOST} from './interfaces/view';
|
import {CONTEXT, FLAGS, LView, LViewFlags, PARENT, QUERIES, RENDERER, TView, T_HOST} from './interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes} from './node_assert';
|
import {assertNodeOfPossibleTypes} from './node_assert';
|
||||||
import {addRemoveViewFromContainer, appendChild, detachView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode, removeView} from './node_manipulation';
|
import {addRemoveViewFromContainer, appendChild, detachView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode, removeView} from './node_manipulation';
|
||||||
import {getParentInjectorTNode} from './node_util';
|
import {getParentInjectorTNode} from './node_util';
|
||||||
import {getLView, getPreviousOrParentTNode} from './state';
|
import {getLView, getPreviousOrParentTNode} from './state';
|
||||||
import {getParentInjectorView, hasParentInjector} from './util/injector_utils';
|
import {getParentInjectorView, hasParentInjector} from './util/injector_utils';
|
||||||
import {findComponentView} from './util/view_traversal_utils';
|
import {findComponentView} from './util/view_traversal_utils';
|
||||||
import {getComponentViewByIndex, getNativeByTNode, isComponent, isLContainer, isRootView} from './util/view_utils';
|
import {getComponentViewByIndex, getNativeByTNode, isComponent, isLContainer, isRootView, viewAttachedToChangeDetector, viewAttachedToContainer} from './util/view_utils';
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,6 +236,12 @@ export function createContainerRef(
|
||||||
const lView = (viewRef as ViewRef<any>)._lView !;
|
const lView = (viewRef as ViewRef<any>)._lView !;
|
||||||
const adjustedIdx = this._adjustIndex(index);
|
const adjustedIdx = this._adjustIndex(index);
|
||||||
|
|
||||||
|
if (viewAttachedToContainer(lView)) {
|
||||||
|
// If view is already attached, fall back to move() so we clean up
|
||||||
|
// references appropriately.
|
||||||
|
return this.move(viewRef, adjustedIdx);
|
||||||
|
}
|
||||||
|
|
||||||
insertView(lView, this._lContainer, adjustedIdx);
|
insertView(lView, this._lContainer, adjustedIdx);
|
||||||
|
|
||||||
const beforeNode =
|
const beforeNode =
|
||||||
|
@ -253,8 +259,8 @@ export function createContainerRef(
|
||||||
throw new Error('Cannot move a destroyed View in a ViewContainer!');
|
throw new Error('Cannot move a destroyed View in a ViewContainer!');
|
||||||
}
|
}
|
||||||
const index = this.indexOf(viewRef);
|
const index = this.indexOf(viewRef);
|
||||||
this.detach(index);
|
if (index !== -1) this.detach(index);
|
||||||
this.insert(viewRef, this._adjustIndex(newIndex));
|
this.insert(viewRef, newIndex);
|
||||||
return viewRef;
|
return viewRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/**
|
||||||
|
* @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, QueryList, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
|
||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
|
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
|
||||||
|
|
||||||
|
describe('ViewContainerRef', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({declarations: [ViewContainerRefComp, ViewContainerRefApp]});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('insert', () => {
|
||||||
|
it('should not blow up on destroy when inserting a view that is already attached', () => {
|
||||||
|
const fixture = TestBed.createComponent(ViewContainerRefApp);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const template0 = fixture.componentInstance.vcrComp.templates.first;
|
||||||
|
const viewContainerRef = fixture.componentInstance.vcrComp.vcr;
|
||||||
|
const ref0 = viewContainerRef.createEmbeddedView(template0);
|
||||||
|
|
||||||
|
// Insert the view again at the same index
|
||||||
|
viewContainerRef.insert(ref0, 0);
|
||||||
|
|
||||||
|
expect(() => { fixture.destroy(); }).not.toThrow();
|
||||||
|
|
||||||
|
expect(fixture.nativeElement.textContent).toEqual('0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move views if they are already attached', () => {
|
||||||
|
const fixture = TestBed.createComponent(ViewContainerRefApp);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const templates = fixture.componentInstance.vcrComp.templates.toArray();
|
||||||
|
const viewContainerRef = fixture.componentInstance.vcrComp.vcr;
|
||||||
|
const ref0 = viewContainerRef.createEmbeddedView(templates[0]);
|
||||||
|
const ref1 = viewContainerRef.createEmbeddedView(templates[1]);
|
||||||
|
const ref2 = viewContainerRef.createEmbeddedView(templates[2]);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(fixture.nativeElement.textContent).toEqual('012');
|
||||||
|
|
||||||
|
// Insert the view again at a different index
|
||||||
|
viewContainerRef.insert(ref0, 2);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
// In Ivy, we correctly move the "0" view to index 2. VE
|
||||||
|
// has a bug that duplicates the view, so it's at index 1.
|
||||||
|
if (ivyEnabled) {
|
||||||
|
expect(fixture.nativeElement.textContent).toEqual('120');
|
||||||
|
} else {
|
||||||
|
expect(fixture.nativeElement.textContent).toEqual('102');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('move', () => {
|
||||||
|
onlyInIvy('Ivy will insert detached views in move')
|
||||||
|
.it('should insert detached views in move()', () => {
|
||||||
|
const fixture = TestBed.createComponent(ViewContainerRefApp);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const templates = fixture.componentInstance.vcrComp.templates.toArray();
|
||||||
|
const viewContainerRef = fixture.componentInstance.vcrComp.vcr;
|
||||||
|
const ref0 = viewContainerRef.createEmbeddedView(templates[0]);
|
||||||
|
const ref1 = viewContainerRef.createEmbeddedView(templates[1]);
|
||||||
|
const ref2 = viewContainerRef.createEmbeddedView(templates[2]);
|
||||||
|
|
||||||
|
viewContainerRef.detach(0);
|
||||||
|
viewContainerRef.move(ref0, 0);
|
||||||
|
|
||||||
|
expect(fixture.nativeElement.textContent).toEqual('012');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'view-container-ref-comp',
|
||||||
|
template: `
|
||||||
|
<ng-template #ref0>0</ng-template>
|
||||||
|
<ng-template #ref1>1</ng-template>
|
||||||
|
<ng-template #ref2>2</ng-template>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class ViewContainerRefComp {
|
||||||
|
@ViewChildren(TemplateRef) templates !: QueryList<TemplateRef<any>>;
|
||||||
|
|
||||||
|
constructor(public vcr: ViewContainerRef) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'view-container-ref-app',
|
||||||
|
template: `
|
||||||
|
<view-container-ref-comp></view-container-ref-comp>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class ViewContainerRefApp {
|
||||||
|
@ViewChild(ViewContainerRefComp) vcrComp !: ViewContainerRefComp;
|
||||||
|
}
|
|
@ -654,6 +654,6 @@
|
||||||
"name": "unwrapRNode"
|
"name": "unwrapRNode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "viewAttached"
|
"name": "viewAttachedToChangeDetector"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -474,6 +474,6 @@
|
||||||
"name": "unwrapRNode"
|
"name": "unwrapRNode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "viewAttached"
|
"name": "viewAttachedToChangeDetector"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -1296,7 +1296,10 @@
|
||||||
"name": "valueExists"
|
"name": "valueExists"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "viewAttached"
|
"name": "viewAttachedToChangeDetector"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "viewAttachedToContainer"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "walkTNodeTree"
|
"name": "walkTNodeTree"
|
||||||
|
|
|
@ -25,218 +25,6 @@ window.testBlocklist = {
|
||||||
"error": "Error: Expected '<pizza-msg><p>Pizza</p><p>Chocolate</p></pizza-msg>' to be '', 'Expected the DomPortalOutlet to be empty after detach'.",
|
"error": "Error: Expected '<pizza-msg><p>Pizza</p><p>Chocolate</p></pizza-msg>' to be '', 'Expected the DomPortalOutlet to be empty after detach'.",
|
||||||
"notes": "Unknown"
|
"notes": "Unknown"
|
||||||
},
|
},
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render initial state": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the data length": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the viewport size": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport size": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the rendered range": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the rendered content offset": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the scroll offset": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the rendered content size": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should measure range size": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set total content size": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set total content size in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set a class based on the orientation": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set the vertical class if an invalid orientation is set": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set rendered range": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set content offset to top of content": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set content offset to bottom of content": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to offset": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to index": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to offset in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to index in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should output scrolled index": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls down": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls up": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render buffer element at the end when scrolled to the top": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render buffer element at the start and end when scrolled to the middle": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render buffer element at the start when scrolled to the bottom": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should handle dynamic item size": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should handle dynamic buffer size": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should handle dynamic item array": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls right in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls left in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should work with an Observable": {
|
|
||||||
"error": "TypeError: Cannot read property 'getRenderedRange' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should work with a DataSource": {
|
|
||||||
"error": "TypeError: Cannot read property 'getRenderedRange' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should trackBy value by default": {
|
|
||||||
"error": "Error: <spyOn> : could not find an object to spy upon for detach()",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should trackBy index when specified": {
|
|
||||||
"error": "Error: <spyOn> : could not find an object to spy upon for detach()",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should recycle views when template cache is large enough to accommodate": {
|
|
||||||
"error": "Error: <spyOn> : could not find an object to spy upon for createEmbeddedView()",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should not recycle views when template cache is full": {
|
|
||||||
"error": "Error: <spyOn> : could not find an object to spy upon for createEmbeddedView()",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render up to maxBufferPx when buffer dips below minBufferPx": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should throw if maxBufferPx is less than minBufferPx": {
|
|
||||||
"error": "Error: Uncaught (in promise): TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should register and degregister with ScrollDispatcher": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should emit on viewChange inside the Angular zone": {
|
|
||||||
"error": "TypeError: Cannot read property 'viewChange' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should not throw when disposing of a view that will not fit in the cache": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with RTL direction should initially be scrolled all the way right and showing the first item in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'elementRef' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with RTL direction should scroll through items as user scrolls to the left in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'elementRef' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with RTL direction should interpret scrollToOffset amount as an offset from the right in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'elementRef' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with RTL direction should scroll to the correct index in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'elementRef' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with RTL direction should emit the scrolled to index in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'elementRef' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with RTL direction should set total content size": {
|
|
||||||
"error": "TypeError: Cannot read property 'elementRef' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with RTL direction should set total content size in horizontal mode": {
|
|
||||||
"error": "TypeError: Cannot read property 'elementRef' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with AutoSizeVirtualScrollStrategy should render initial state for uniform items": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with AutoSizeVirtualScrollStrategy should render extra content if first item is smaller than average": {
|
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkVirtualScrollViewport with AutoSizeVirtualScrollStrategy should throw if maxBufferPx is less than minBufferPx": {
|
|
||||||
"error": "Error: Uncaught (in promise): TypeError: Cannot read property 'nativeElement' of undefined",
|
|
||||||
"notes": "FW-1114: Ivy doesn't support inserting same view instance multiple times"
|
|
||||||
},
|
|
||||||
"CdkAccordion should not register nested items to the same accordion": {
|
|
||||||
"error": "TypeError: Cannot read property 'accordion' of undefined",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"CdkDrag in a drop container should be able to customize the preview element": {
|
"CdkDrag in a drop container should be able to customize the preview element": {
|
||||||
"error": "Error: Expected cdk-drag cdk-drag-preview to contain 'custom-preview'.",
|
"error": "Error: Expected cdk-drag cdk-drag-preview to contain 'custom-preview'.",
|
||||||
"notes": "Unknown"
|
"notes": "Unknown"
|
||||||
|
@ -341,62 +129,14 @@ window.testBlocklist = {
|
||||||
"error": "Error: Failed: Expected node descendant num to be 2 but was 0",
|
"error": "Error: Failed: Expected node descendant num to be 2 but was 0",
|
||||||
"notes": "Unknown"
|
"notes": "Unknown"
|
||||||
},
|
},
|
||||||
"MatButton should apply class based on color attribute": {
|
"MatInput without forms validates the type": {
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
"error": "Error: Input type \"file\" isn't supported by matInput.",
|
||||||
"notes": "Unknown"
|
"notes": "Unknown"
|
||||||
},
|
},
|
||||||
"MatButton should expose the ripple instance": {
|
"MatInput with textarea autosize should work in a step": {
|
||||||
"error": "Error: Expected undefined to be truthy.",
|
"error": "TypeError: Cannot read property 'getBoundingClientRect' of null",
|
||||||
"notes": "Unknown"
|
"notes": "Unknown"
|
||||||
},
|
},
|
||||||
"MatButton should not clear previous defined classes": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton button[mat-fab] should have accent palette by default": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton button[mat-mini-fab] should have accent palette by default": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton button[mat-button] should not increment if disabled": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton button[mat-button] should disable the native button element": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton a[mat-button] should not redirect if disabled": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton a[mat-button] should remove tabindex if disabled": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton a[mat-button] should add aria-disabled attribute if disabled": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton a[mat-button] should not add aria-disabled attribute if disabled is false": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton a[mat-button] should be able to set a custom tabindex": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton button ripples should disable the ripple if matRippleDisabled input is set": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatButton button ripples should disable the ripple when the button is disabled": {
|
|
||||||
"error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.",
|
|
||||||
"notes": "FW-1037: Host bindings for host objects in metadata are inherited"
|
|
||||||
},
|
|
||||||
"MatChipList StandardChipList basic behaviors should toggle the chips disabled state based on whether it is disabled": {
|
"MatChipList StandardChipList basic behaviors should toggle the chips disabled state based on whether it is disabled": {
|
||||||
"error": "Error: Expected true to be false.",
|
"error": "Error: Expected true to be false.",
|
||||||
"notes": "Unknown"
|
"notes": "Unknown"
|
||||||
|
@ -525,12 +265,8 @@ window.testBlocklist = {
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
"error": "TypeError: Cannot read property 'nativeElement' of undefined",
|
||||||
"notes": "Unknown"
|
"notes": "Unknown"
|
||||||
},
|
},
|
||||||
"MatSlideToggle without forms custom action configuration should not change value on dragging when drag action is noop": {
|
|
||||||
"error": "Error: Expected mat-slide-toggle-thumb-container to contain 'mat-dragging'.",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"MatSidenav should be fixed position when in fixed mode": {
|
"MatSidenav should be fixed position when in fixed mode": {
|
||||||
"error": "Error: Expected ng-tns-c23412-0 mat-drawer ng-trigger ng-trigger-transform mat-drawer-over ng-star-inserted to contain 'mat-sidenav-fixed'.",
|
"error": "Error: Expected ng-tns-c28435-0 ng-trigger ng-trigger-transform mat-drawer mat-drawer-over ng-star-inserted to contain 'mat-sidenav-fixed'.",
|
||||||
"notes": "FW-1081: Static host classes don't work if component has superclass with host classes"
|
"notes": "FW-1081: Static host classes don't work if component has superclass with host classes"
|
||||||
},
|
},
|
||||||
"MatSidenav should set fixed bottom and top when in fixed mode": {
|
"MatSidenav should set fixed bottom and top when in fixed mode": {
|
||||||
|
@ -569,34 +305,10 @@ window.testBlocklist = {
|
||||||
"error": "TypeError: Cannot read property 'click' of undefined",
|
"error": "TypeError: Cannot read property 'click' of undefined",
|
||||||
"notes": "FW-1081: Static host classes don't work if component has superclass with host classes"
|
"notes": "FW-1081: Static host classes don't work if component has superclass with host classes"
|
||||||
},
|
},
|
||||||
"MatGridList should throw error if rowHeight ratio is invalid": {
|
|
||||||
"error": "Error: mat-grid-list: invalid ratio given for row-height: \"4:3:2\"",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"MatInput without forms validates the type": {
|
|
||||||
"error": "Error: Input type \"file\" isn't supported by matInput.",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"MatInput with textarea autosize should work in a step": {
|
|
||||||
"error": "TypeError: Cannot read property 'getBoundingClientRect' of null",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"Dialog should set the proper animation states": {
|
"Dialog should set the proper animation states": {
|
||||||
"error": "TypeError: Cannot read property 'componentInstance' of null",
|
"error": "TypeError: Cannot read property 'componentInstance' of null",
|
||||||
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
||||||
},
|
},
|
||||||
"FullscreenOverlayContainer should open an overlay inside a fullscreen element and move it to the body": {
|
|
||||||
"error": "Error: Must provide a portal to attach",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"FullscreenOverlayContainer should open an overlay inside the body and move it to a fullscreen element": {
|
|
||||||
"error": "Error: Must provide a portal to attach",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"OverlayContainer should remove the overlay container element from the DOM on destruction": {
|
|
||||||
"error": "Error: Must provide a portal to attach",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"MatAutocomplete aria should set role of autocomplete panel to listbox": {
|
"MatAutocomplete aria should set role of autocomplete panel to listbox": {
|
||||||
"error": "TypeError: Cannot read property 'nativeElement' of null",
|
"error": "TypeError: Cannot read property 'nativeElement' of null",
|
||||||
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
||||||
|
@ -609,10 +321,6 @@ window.testBlocklist = {
|
||||||
"error": "TypeError: Cannot read property 'componentInstance' of null",
|
"error": "TypeError: Cannot read property 'componentInstance' of null",
|
||||||
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
||||||
},
|
},
|
||||||
"MatMenu should close the menu when using the CloseScrollStrategy": {
|
|
||||||
"error": "TypeError: Cannot read property 'openMenu' of undefined",
|
|
||||||
"notes": "Unknown"
|
|
||||||
},
|
|
||||||
"MatMenu animations should enable ripples on items by default": {
|
"MatMenu animations should enable ripples on items by default": {
|
||||||
"error": "TypeError: Cannot read property 'query' of null",
|
"error": "TypeError: Cannot read property 'query' of null",
|
||||||
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
"notes": "FW-1059: DebugNode.query should query nodes in the logical tree"
|
||||||
|
|
Loading…
Reference in New Issue