From c4123748543c46aa0e78fb0cfceab265ce926907 Mon Sep 17 00:00:00 2001 From: Marc Laval Date: Fri, 22 Mar 2019 18:24:21 +0100 Subject: [PATCH] fix(ivy): DebugNode.query should query nodes in the logical tree (#29480) PR Close #29480 --- .../test/ng_package/core_package.spec.ts | 2 +- .../compiler-cli/test/ngtools_api_spec.ts | 2 +- packages/core/src/debug/debug_node.ts | 143 +++++++++++++++-- .../animation_query_integration_spec.ts | 2 +- .../animation_router_integration_spec.ts | 1 - packages/core/test/debug/debug_node_spec.ts | 144 +++++++++++++++++- .../test/linker/ng_module_integration_spec.ts | 2 +- .../linker/projection_integration_spec.ts | 103 ++++++------- .../test/linker/query_integration_spec.ts | 2 +- .../test/linker/security_integration_spec.ts | 2 +- .../source_map_integration_node_only_spec.ts | 2 +- packages/core/test/render3/lifecycle_spec.ts | 1 - .../test/animation_renderer_spec.ts | 1 - .../private/testing/src/ivy_test_selectors.ts | 89 +---------- .../angular_material_test_blocklist.js | 36 ----- 15 files changed, 333 insertions(+), 199 deletions(-) diff --git a/packages/bazel/test/ng_package/core_package.spec.ts b/packages/bazel/test/ng_package/core_package.spec.ts index 57ce76a52c..934ad3682c 100644 --- a/packages/bazel/test/ng_package/core_package.spec.ts +++ b/packages/bazel/test/ng_package/core_package.spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {fixmeIvy, ivyEnabled, obsoleteInIvy} from '@angular/private/testing'; +import {ivyEnabled, obsoleteInIvy} from '@angular/private/testing'; import * as path from 'path'; import * as shx from 'shelljs'; diff --git a/packages/compiler-cli/test/ngtools_api_spec.ts b/packages/compiler-cli/test/ngtools_api_spec.ts index 65f5a8adaa..4eeb2d7c6d 100644 --- a/packages/compiler-cli/test/ngtools_api_spec.ts +++ b/packages/compiler-cli/test/ngtools_api_spec.ts @@ -7,7 +7,7 @@ */ import {__NGTOOLS_PRIVATE_API_2 as NgTools_InternalApi_NG_2} from '@angular/compiler-cli'; -import {fixmeIvy, ivyEnabled} from '@angular/private/testing'; +import {ivyEnabled} from '@angular/private/testing'; import * as path from 'path'; import * as ts from 'typescript'; diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index 5ba74e1e18..52044fe16f 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -8,13 +8,16 @@ import {Injector} from '../di'; import {getViewComponent} from '../render3/global_utils_api'; -import {TNode} from '../render3/interfaces/node'; +import {LContainer, NATIVE, VIEWS} from '../render3/interfaces/container'; +import {TElementNode, TNode, TNodeFlags, TNodeType} from '../render3/interfaces/node'; import {StylingIndex} from '../render3/interfaces/styling'; -import {LView, TData, TVIEW} from '../render3/interfaces/view'; +import {LView, NEXT, PARENT, TData, TVIEW, T_HOST} from '../render3/interfaces/view'; import {getProp, getValue, isClassBasedValue} from '../render3/styling/class_and_style_bindings'; import {getStylingContext} from '../render3/styling/util'; import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, isBrowserEvents, loadLContext, loadLContextFromNode} from '../render3/util/discovery_utils'; import {INTERPOLATION_DELIMITER, isPropMetadataString, renderStringify} from '../render3/util/misc_utils'; +import {findComponentView} from '../render3/util/view_traversal_utils'; +import {getComponentViewByIndex, getNativeByTNode, isComponent, isLContainer} from '../render3/util/view_utils'; import {assertDomNode} from '../util/assert'; import {DebugContext} from '../view/index'; @@ -368,13 +371,13 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme queryAll(predicate: Predicate): DebugElement[] { const matches: DebugElement[] = []; - _queryNodeChildrenR3(this, predicate, matches, true); + _queryAllR3(this, predicate, matches, true); return matches; } queryAllNodes(predicate: Predicate): DebugNode[] { const matches: DebugNode[] = []; - _queryNodeChildrenR3(this, predicate, matches, false); + _queryAllR3(this, predicate, matches, false); return matches; } @@ -387,20 +390,130 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme } } -function _queryNodeChildrenR3( - parentNode: DebugNode, predicate: Predicate, matches: DebugNode[], +/** + * Walk the TNode tree to find matches for the predicate, skipping the parent element. + * + * @param parentElement the element from which the walk is started + * @param predicate the predicate to match + * @param matches the list of positive matches + * @param elementsOnly whether only elements should be searched + */ +function _queryAllR3( + parentElement: DebugElement, predicate: Predicate, matches: DebugNode[], elementsOnly: boolean) { - if (parentNode instanceof DebugElement__POST_R3__) { - parentNode.childNodes.forEach(node => { - if (predicate(node)) { - matches.push(node); + const context = loadLContext(parentElement.nativeNode) !; + const parentTNode = context.lView[TVIEW].data[context.nodeIndex] as TNode; + // This the fixture's debug element, so this is always a component view. + const lView = context.lView[parentTNode.index]; + const tNode = lView[TVIEW].firstChild; + _queryNodeChildrenR3(tNode, lView, predicate, matches, elementsOnly); +} + +/** + * Recursively match the current TNode against the predicate, and goes on with the next ones. + * + * @param tNode the current TNode + * @param lView the LView of this TNode + * @param predicate the predicate to match + * @param matches the list of positive matches + * @param elementsOnly whether only elements should be searched + */ +function _queryNodeChildrenR3( + tNode: TNode, lView: LView, predicate: Predicate, matches: DebugNode[], + elementsOnly: boolean) { + // For each type of TNode, specific logic is executed. + if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) { + // Case 1: the TNode is an element + // The native node has to be checked. + _addQueryMatchR3(getNativeByTNode(tNode, lView), predicate, matches, elementsOnly); + if (isComponent(tNode)) { + // If the element is the host of a component, then all nodes in its view have to be processed. + // Note: the component's content (tNode.child) will be processed from the insertion points. + const componentView = getComponentViewByIndex(tNode.index, lView); + if (componentView && componentView[TVIEW].firstChild) + _queryNodeChildrenR3( + componentView[TVIEW].firstChild !, componentView, predicate, matches, elementsOnly); + } else { + // Otherwise, its children have to be processed. + if (tNode.child) _queryNodeChildrenR3(tNode.child, lView, predicate, matches, elementsOnly); + } + // In all cases, if a dynamic container exists for this node, each view inside it has to be + // processed. + const nodeOrContainer = lView[tNode.index]; + if (isLContainer(nodeOrContainer)) { + _queryNodeChildrenInContainerR3(nodeOrContainer, predicate, matches, elementsOnly); + } + } else if (tNode.type === TNodeType.Container) { + // Case 2: the TNode is a container + // The native node has to be checked. + const lContainer = lView[tNode.index]; + _addQueryMatchR3(lContainer[NATIVE], predicate, matches, elementsOnly); + // Each view inside the container has to be processed. + _queryNodeChildrenInContainerR3(lContainer, predicate, matches, elementsOnly); + } else if (tNode.type === TNodeType.Projection) { + // Case 3: the TNode is a projection insertion point (i.e. a ). + // The nodes projected at this location all need to be processed. + const componentView = findComponentView(lView !); + const componentHost = componentView[T_HOST] as TElementNode; + const head: TNode|null = + (componentHost.projection as(TNode | null)[])[tNode.projection as number]; + + if (Array.isArray(head)) { + for (let nativeNode of head) { + _addQueryMatchR3(nativeNode, predicate, matches, elementsOnly); } - if (node instanceof DebugElement__POST_R3__) { - if (elementsOnly ? node.nativeElement : true) { - _queryNodeChildrenR3(node, predicate, matches, elementsOnly); - } + } else { + if (head) { + const nextLView = componentView[PARENT] !as LView; + const nextTNode = nextLView[TVIEW].data[head.index] as TNode; + _queryNodeChildrenR3(nextTNode, nextLView, predicate, matches, elementsOnly); } - }); + } + } else { + // Case 4: the TNode is a view. + if (tNode.child) { + _queryNodeChildrenR3(tNode.child, lView, predicate, matches, elementsOnly); + } + } + // To determine the next node to be processed, we need to use the next or the projectionNext link, + // depending on whether the current node has been projected. + const nextTNode = (tNode.flags & TNodeFlags.isProjected) ? tNode.projectionNext : tNode.next; + if (nextTNode) { + _queryNodeChildrenR3(nextTNode, lView, predicate, matches, elementsOnly); + } +} + +/** + * Process all TNodes in a given container. + * + * @param lContainer the container to be processed + * @param predicate the predicate to match + * @param matches the list of positive matches + * @param elementsOnly whether only elements should be searched + */ +function _queryNodeChildrenInContainerR3( + lContainer: LContainer, predicate: Predicate, matches: DebugNode[], + elementsOnly: boolean) { + for (let i = 0; i < lContainer[VIEWS].length; i++) { + const childView = lContainer[VIEWS][i]; + _queryNodeChildrenR3(childView[TVIEW].node !, childView, predicate, matches, elementsOnly); + } +} + +/** + * Match the current native node against the predicate. + * + * @param nativeNode the current native node + * @param predicate the predicate to match + * @param matches the list of positive matches + * @param elementsOnly whether only elements should be searched + */ +function _addQueryMatchR3( + nativeNode: any, predicate: Predicate, matches: DebugNode[], elementsOnly: boolean) { + const debugNode = getDebugNode(nativeNode); + if (debugNode && (elementsOnly ? debugNode instanceof DebugElement__POST_R3__ : true) && + predicate(debugNode)) { + matches.push(debugNode); } } diff --git a/packages/core/test/animation/animation_query_integration_spec.ts b/packages/core/test/animation/animation_query_integration_spec.ts index a2c8d90458..6a4a339765 100644 --- a/packages/core/test/animation/animation_query_integration_spec.ts +++ b/packages/core/test/animation/animation_query_integration_spec.ts @@ -14,7 +14,7 @@ import {CommonModule} from '@angular/common'; import {Component, HostBinding, ViewChild} from '@angular/core'; import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; -import {fixmeIvy, ivyEnabled} from '@angular/private/testing'; +import {ivyEnabled} from '@angular/private/testing'; import {HostListener} from '../../src/metadata/directives'; diff --git a/packages/core/test/animation/animation_router_integration_spec.ts b/packages/core/test/animation/animation_router_integration_spec.ts index e904623ec9..3225a8727f 100644 --- a/packages/core/test/animation/animation_router_integration_spec.ts +++ b/packages/core/test/animation/animation_router_integration_spec.ts @@ -11,7 +11,6 @@ import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/brow import {Component, HostBinding} from '@angular/core'; import {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; -import {fixmeIvy} from '@angular/private/testing'; import {ActivatedRoute, Router, RouterOutlet} from '@angular/router'; import {RouterTestingModule} from '@angular/router/testing'; diff --git a/packages/core/test/debug/debug_node_spec.ts b/packages/core/test/debug/debug_node_spec.ts index 29df30db85..54713b2019 100644 --- a/packages/core/test/debug/debug_node_spec.ts +++ b/packages/core/test/debug/debug_node_spec.ts @@ -7,7 +7,7 @@ */ -import {Component, Directive, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA} from '@angular/core'; +import {Component, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; import {ComponentFixture, TestBed, async} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; @@ -154,6 +154,15 @@ class BankAccount { normalizedBankName !: string; } +@Component({ + template: ` +
Some content
+ ` +}) +class SimpleContentComp { + @ViewChild('content') content !: ElementRef; +} + @Component({ selector: 'test-app', template: ` @@ -202,6 +211,7 @@ class HostClassBindingCmp { BankAccount, TestCmpt, HostClassBindingCmp, + SimpleContentComp, ], providers: [Logger], schemas: [NO_ERRORS_SCHEMA], @@ -369,6 +379,122 @@ class HostClassBindingCmp { expect(debugElement).toBeTruthy(); }); + it('should query re-projected child elements by directive', () => { + @Directive({selector: 'example-directive-a'}) + class ExampleDirectiveA { + } + + @Component({ + selector: 'proxy-component', + template: ` + + ` + }) + class ProxyComponent { + } + + @Component({ + selector: 'wrapper-component', + template: ` + + + + + ` + }) + class WrapperComponent { + } + + TestBed.configureTestingModule({ + declarations: [ + ProxyComponent, + WrapperComponent, + ExampleDirectiveA, + ] + }); + + TestBed.overrideTemplate(TestApp, ` +
+ +
`); + + const fixture = TestBed.createComponent(TestApp); + fixture.detectChanges(); + + const debugElements = fixture.debugElement.queryAll(By.directive(ExampleDirectiveA)); + expect(debugElements.length).toBe(1); + }); + + it('should query directives on containers before directives in a view', () => { + @Directive({selector: '[text]'}) + class TextDirective { + @Input() text: string|undefined; + } + + TestBed.configureTestingModule({declarations: [TextDirective]}); + TestBed.overrideTemplate( + TestApp, + `
`); + + const fixture = TestBed.createComponent(TestApp); + fixture.detectChanges(); + + const debugNodes = fixture.debugElement.queryAllNodes(By.directive(TextDirective)); + expect(debugNodes.length).toBe(2); + expect(debugNodes[0].injector.get(TextDirective).text).toBe('first'); + expect(debugNodes[1].injector.get(TextDirective).text).toBe('second'); + }); + + it('should query directives on views moved in the DOM', () => { + @Directive({selector: '[text]'}) + class TextDirective { + @Input() text: string|undefined; + } + + @Directive({selector: '[moveView]'}) + class ViewManipulatingDirective { + constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef) {} + + insert() { this._vcRef.createEmbeddedView(this._tplRef); } + + removeFromTheDom() { + const viewRef = this._vcRef.get(0) as EmbeddedViewRef; + viewRef.rootNodes.forEach(rootNode => { getDOM().remove(rootNode); }); + } + } + + TestBed.configureTestingModule({declarations: [TextDirective, ViewManipulatingDirective]}); + TestBed.overrideTemplate( + TestApp, `
`); + + const fixture = TestBed.createComponent(TestApp); + fixture.detectChanges(); + + const viewMover = + fixture.debugElement.queryAllNodes(By.directive(ViewManipulatingDirective))[0] + .injector.get(ViewManipulatingDirective); + + let debugNodes = fixture.debugElement.queryAllNodes(By.directive(TextDirective)); + + // we've got just one directive on + expect(debugNodes.length).toBe(1); + expect(debugNodes[0].injector.get(TextDirective).text).toBe('first'); + + // insert a view - now we expect to find 2 directive instances + viewMover.insert(); + fixture.detectChanges(); + debugNodes = fixture.debugElement.queryAllNodes(By.directive(TextDirective)); + expect(debugNodes.length).toBe(2); + + // remove a view from the DOM (equivalent to moving it around) + // the logical tree is the same but DOM has changed + viewMover.removeFromTheDom(); + debugNodes = fixture.debugElement.queryAllNodes(By.directive(TextDirective)); + expect(debugNodes.length).toBe(2); + expect(debugNodes[0].injector.get(TextDirective).text).toBe('first'); + expect(debugNodes[1].injector.get(TextDirective).text).toBe('second'); + }); + it('should list providerTokens', () => { fixture = TestBed.createComponent(ParentComp); fixture.detectChanges(); @@ -489,5 +615,21 @@ class HostClassBindingCmp { }); }); + it('should be able to query for elements that are not in the same DOM tree anymore', () => { + fixture = TestBed.createComponent(SimpleContentComp); + fixture.detectChanges(); + + const parent = getDOM().parentElement(fixture.nativeElement) !; + const content = fixture.componentInstance.content.nativeElement; + + // Move the content element outside the component + // so that it can't be reached via querySelector. + getDOM().appendChild(parent, content); + + expect(fixture.debugElement.query(By.css('.content'))).toBeTruthy(); + + getDOM().remove(content); + }); + }); } diff --git a/packages/core/test/linker/ng_module_integration_spec.ts b/packages/core/test/linker/ng_module_integration_spec.ts index 1a0132d137..3be2042dc4 100644 --- a/packages/core/test/linker/ng_module_integration_spec.ts +++ b/packages/core/test/linker/ng_module_integration_spec.ts @@ -14,7 +14,7 @@ import {NgModuleData} from '@angular/core/src/view/types'; import {tokenKey} from '@angular/core/src/view/util'; import {ComponentFixture, TestBed, inject} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; +import {modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; import {InternalNgModuleRef, NgModuleFactory} from '../../src/linker/ng_module_factory'; import {clearModulesForTest} from '../../src/linker/ng_module_factory_loader'; diff --git a/packages/core/test/linker/projection_integration_spec.ts b/packages/core/test/linker/projection_integration_spec.ts index 1789efccb7..d55447c3ea 100644 --- a/packages/core/test/linker/projection_integration_spec.ts +++ b/packages/core/test/linker/projection_integration_spec.ts @@ -11,7 +11,7 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, modifiedInIvy} from '@angular/private/testing'; +import {modifiedInIvy} from '@angular/private/testing'; describe('projection', () => { beforeEach(() => TestBed.configureTestingModule({declarations: [MainComp, OtherComp, Simple]})); @@ -511,25 +511,23 @@ describe('projection', () => { }); } - fixmeIvy('FW-869: debugElement.queryAllNodes returns nodes in the wrong order') - .it('should support nested conditionals that contain ng-contents', () => { - TestBed.configureTestingModule( - {declarations: [ConditionalTextComponent, ManualViewportDirective]}); - TestBed.overrideComponent( - MainComp, {set: {template: `a`}}); - const main = TestBed.createComponent(MainComp); + it('should support nested conditionals that contain ng-contents', () => { + TestBed.configureTestingModule( + {declarations: [ConditionalTextComponent, ManualViewportDirective]}); + TestBed.overrideComponent( + MainComp, {set: {template: `a`}}); + const main = TestBed.createComponent(MainComp); - expect(main.nativeElement).toHaveText('MAIN()'); + expect(main.nativeElement).toHaveText('MAIN()'); - let viewportElement = - main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0]; - viewportElement.injector.get(ManualViewportDirective).show(); - expect(main.nativeElement).toHaveText('MAIN(FIRST())'); + let viewportElement = main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0]; + viewportElement.injector.get(ManualViewportDirective).show(); + expect(main.nativeElement).toHaveText('MAIN(FIRST())'); - viewportElement = main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[1]; - viewportElement.injector.get(ManualViewportDirective).show(); - expect(main.nativeElement).toHaveText('MAIN(FIRST(SECOND(a)))'); - }); + viewportElement = main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[1]; + viewportElement.injector.get(ManualViewportDirective).show(); + expect(main.nativeElement).toHaveText('MAIN(FIRST(SECOND(a)))'); + }); it('should allow to switch the order of nested components via ng-content', () => { TestBed.configureTestingModule({declarations: [CmpA, CmpB, CmpD, CmpC]}); @@ -639,49 +637,48 @@ describe('projection', () => { expect(main.nativeElement).toHaveText('ABC'); }); - fixmeIvy('FW-869: debugElement.queryAllNodes returns nodes in the wrong order') - .it('should project filled view containers into a view container', () => { - TestBed.configureTestingModule( - {declarations: [ConditionalContentComponent, ManualViewportDirective]}); - TestBed.overrideComponent(MainComp, { - set: { - template: '' + - '
A
' + - 'B' + - '
C
' + - '
D
' + - '
' - } - }); - const main = TestBed.createComponent(MainComp); + it('should project filled view containers into a view container', () => { + TestBed.configureTestingModule( + {declarations: [ConditionalContentComponent, ManualViewportDirective]}); + TestBed.overrideComponent(MainComp, { + set: { + template: '' + + '
A
' + + 'B' + + '
C
' + + '
D
' + + '
' + } + }); + const main = TestBed.createComponent(MainComp); - const conditionalComp = main.debugElement.query(By.directive(ConditionalContentComponent)); + const conditionalComp = main.debugElement.query(By.directive(ConditionalContentComponent)); - const viewViewportDir = - conditionalComp.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get( - ManualViewportDirective); + const viewViewportDir = + conditionalComp.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get( + ManualViewportDirective); - expect(main.nativeElement).toHaveText('(, D)'); - expect(main.nativeElement).toHaveText('(, D)'); + expect(main.nativeElement).toHaveText('(, D)'); + expect(main.nativeElement).toHaveText('(, D)'); - viewViewportDir.show(); - main.detectChanges(); - expect(main.nativeElement).toHaveText('(AC, D)'); + viewViewportDir.show(); + main.detectChanges(); + expect(main.nativeElement).toHaveText('(AC, D)'); - const contentViewportDir = - conditionalComp.queryAllNodes(By.directive(ManualViewportDirective))[1].injector.get( - ManualViewportDirective); + const contentViewportDir = + conditionalComp.queryAllNodes(By.directive(ManualViewportDirective))[1].injector.get( + ManualViewportDirective); - contentViewportDir.show(); - main.detectChanges(); - expect(main.nativeElement).toHaveText('(ABC, D)'); + contentViewportDir.show(); + main.detectChanges(); + expect(main.nativeElement).toHaveText('(ABC, D)'); - // hide view viewport, and test that it also hides - // the content viewport's views - viewViewportDir.hide(); - main.detectChanges(); - expect(main.nativeElement).toHaveText('(, D)'); - }); + // hide view viewport, and test that it also hides + // the content viewport's views + viewViewportDir.hide(); + main.detectChanges(); + expect(main.nativeElement).toHaveText('(, D)'); + }); describe('projectable nodes', () => { diff --git a/packages/core/test/linker/query_integration_spec.ts b/packages/core/test/linker/query_integration_spec.ts index bd6bd37109..04de5fc493 100644 --- a/packages/core/test/linker/query_integration_spec.ts +++ b/packages/core/test/linker/query_integration_spec.ts @@ -10,7 +10,7 @@ import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, import {ElementRef} from '@angular/core/src/core'; import {ComponentFixture, TestBed, async} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; +import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; import {Subject} from 'rxjs'; import {stringify} from '../../src/util/stringify'; diff --git a/packages/core/test/linker/security_integration_spec.ts b/packages/core/test/linker/security_integration_spec.ts index 8908822d05..f19781414d 100644 --- a/packages/core/test/linker/security_integration_spec.ts +++ b/packages/core/test/linker/security_integration_spec.ts @@ -10,7 +10,7 @@ import {Component, Directive, HostBinding, Input, NO_ERRORS_SCHEMA, ɵivyEnabled import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service'; -import {fixmeIvy, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; +import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; { if (ivyEnabled) { diff --git a/packages/core/test/linker/source_map_integration_node_only_spec.ts b/packages/core/test/linker/source_map_integration_node_only_spec.ts index 09ea288ace..c15b0ee597 100644 --- a/packages/core/test/linker/source_map_integration_node_only_spec.ts +++ b/packages/core/test/linker/source_map_integration_node_only_spec.ts @@ -17,7 +17,7 @@ import {CompilerFacade, ExportedCompilerFacade} from '@angular/core/src/compiler import {getErrorLogger} from '@angular/core/src/errors'; import {resolveComponentResources} from '@angular/core/src/metadata/resource_loading'; import {TestBed, fakeAsync, tick} from '@angular/core/testing'; -import {fixmeIvy, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; +import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; describe('jit source mapping', () => { let resourceLoader: MockResourceLoader; diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index 7cd44217b9..2139c41244 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -14,7 +14,6 @@ import {RenderFlags} from '../../src/render3/interfaces/definition'; import {NgIf} from './common_with_def'; import {ComponentFixture, containerEl, createComponent, renderComponent, renderToHtml, requestAnimationFrame} from './render_util'; -import {fixmeIvy} from '@angular/private/testing'; describe('lifecycles', () => { diff --git a/packages/platform-browser/animations/test/animation_renderer_spec.ts b/packages/platform-browser/animations/test/animation_renderer_spec.ts index 2f26069c0f..83f0b08d4f 100644 --- a/packages/platform-browser/animations/test/animation_renderer_spec.ts +++ b/packages/platform-browser/animations/test/animation_renderer_spec.ts @@ -11,7 +11,6 @@ import {Component, Injectable, NgZone, RendererFactory2, RendererType2, ViewChil import {TestBed} from '@angular/core/testing'; import {BrowserAnimationsModule, ɵAnimationRendererFactory as AnimationRendererFactory, ɵInjectableAnimationEngine as InjectableAnimationEngine} from '@angular/platform-browser/animations'; import {DomRendererFactory2} from '@angular/platform-browser/src/dom/dom_renderer'; -import {fixmeIvy} from '@angular/private/testing'; import {el} from '../../testing/src/browser_util'; diff --git a/packages/private/testing/src/ivy_test_selectors.ts b/packages/private/testing/src/ivy_test_selectors.ts index 38b0ceb47e..516c1b4b91 100644 --- a/packages/private/testing/src/ivy_test_selectors.ts +++ b/packages/private/testing/src/ivy_test_selectors.ts @@ -8,15 +8,6 @@ import {bazelDefineCompileValue} from './bazel_define_compile_value'; -/** - * Set this constant to `true` to run all tests and report which of the tests marked with `fixmeIvy` - * are actually already passing. - * - * This is useful for locating already passing tests. The already passing tests should have their - * `fixmeIvy` removed. - */ -const FIND_PASSING_TESTS = false; - /** * A function to conditionally include a test or a block of tests only when tests run against Ivy. * @@ -35,30 +26,6 @@ const FIND_PASSING_TESTS = false; */ export const ivyEnabled = 'aot' === (bazelDefineCompileValue as string); - -/** - * A function to conditionally skip the execution of tests that are yet to be fixed - * when running against Ivy. - * - * ``` - * fixmeIvy('some reason').describe(...); - * ``` - * - * or - * - * ``` - * fixmeIvy('some reason').it(...); - * ``` - */ -export function fixmeIvy(reason: string): JasmineMethods { - if (FIND_PASSING_TESTS) { - return ivyEnabled ? PASSTHROUGH : IGNORE; - } else { - return ivyEnabled ? IGNORE : PASSTHROUGH; - } -} - - /** * A function to conditionally skip the execution of tests that are not relevant when * running against Ivy. @@ -94,7 +61,7 @@ export function obsoleteInIvy(reason: string): JasmineMethods { * ``` */ export function onlyInIvy(reason: string): JasmineMethods { - return ivyEnabled && !FIND_PASSING_TESTS ? PASSTHROUGH : IGNORE; + return ivyEnabled ? PASSTHROUGH : IGNORE; } /** @@ -123,29 +90,17 @@ export interface JasmineMethods { fit: typeof fit; describe: typeof describe; fdescribe: typeof fdescribe; - fixmeIvy: typeof fixmeIvy; isEnabled: boolean; } const PASSTHROUGH: JasmineMethods = { - it: maybeAppendFindPassingTestsMarker(it), - fit: maybeAppendFindPassingTestsMarker(fit), - describe: maybeAppendFindPassingTestsMarker(describe), - fdescribe: maybeAppendFindPassingTestsMarker(fdescribe), - fixmeIvy: maybeAppendFindPassingTestsMarker(fixmeIvy), + it: it, + fit: fit, + describe: describe, + fdescribe: fdescribe, isEnabled: true, }; -const FIND_PASSING_TESTS_MARKER = '__FIND_PASSING_TESTS_MARKER__'; -function maybeAppendFindPassingTestsMarker(fn: T): T { - return FIND_PASSING_TESTS ? function(...args: any[]) { - if (typeof args[0] == 'string') { - args[0] += FIND_PASSING_TESTS_MARKER; - } - return fn.apply(this, args); - } : fn as any; -} - function noop() {} const IGNORE: JasmineMethods = { @@ -153,39 +108,5 @@ const IGNORE: JasmineMethods = { fit: noop, describe: noop, fdescribe: noop, - fixmeIvy: (reason) => IGNORE, isEnabled: false, }; - -if (FIND_PASSING_TESTS) { - const env = jasmine.getEnv(); - const passingTests: jasmine.CustomReporterResult[] = []; - const stillFailing: jasmine.CustomReporterResult[] = []; - let specCount = 0; - env.clearReporters(); - env.addReporter({ - specDone: function(result: jasmine.CustomReporterResult) { - specCount++; - if (result.fullName.indexOf(FIND_PASSING_TESTS_MARKER) != -1) { - (result.status == 'passed' ? passingTests : stillFailing).push(result); - } - }, - jasmineDone: function(details: jasmine.RunDetails) { - if (passingTests.length) { - passingTests.forEach((result) => { - // tslint:disable-next-line:no-console - console.log('ALREADY PASSING', result.fullName.replace(FIND_PASSING_TESTS_MARKER, '')); - }); - // tslint:disable-next-line:no-console - console.log( - `${specCount} specs,`, // - `${passingTests.length} passing specs,`, // - `${stillFailing.length} still failing specs`); - - } else { - // tslint:disable-next-line:no-console - console.log('NO PASSING TESTS FOUND.'); - } - } - }); -} \ No newline at end of file diff --git a/tools/material-ci/angular_material_test_blocklist.js b/tools/material-ci/angular_material_test_blocklist.js index 5bb4a18c1f..17bf32c8b0 100644 --- a/tools/material-ci/angular_material_test_blocklist.js +++ b/tools/material-ci/angular_material_test_blocklist.js @@ -24,42 +24,6 @@ window.testBlocklist = { "MatSidenav should set fixed bottom and top when in fixed mode": { "error": "Error: Expected '' to be '20px'.", "notes": "FW-1132: Host class bindings don't work if super class has host class bindings" - }, - "Dialog should set the proper animation states": { - "error": "TypeError: Cannot read property 'componentInstance' of null", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatAutocomplete aria should set role of autocomplete panel to listbox": { - "error": "TypeError: Cannot read property 'nativeElement' of null", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatAutocomplete aria should set aria-owns based on the attached autocomplete": { - "error": "TypeError: Cannot read property 'nativeElement' of null", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatDialog should set the proper animation states": { - "error": "TypeError: Cannot read property 'componentInstance' of null", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatMenu animations should enable ripples on items by default": { - "error": "TypeError: Cannot read property 'query' of null", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatMenu animations should disable ripples on disabled items": { - "error": "TypeError: Cannot read property 'query' of undefined", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatMenu animations should disable ripples if disableRipple is set": { - "error": "TypeError: Cannot read property 'query' of undefined", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatMenu nested menu should close submenu when hovering over disabled sibling item": { - "error": "TypeError: Cannot read property 'nativeElement' of undefined", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" - }, - "MatMenu nested menu should not open submenu when hovering over disabled trigger": { - "error": "TypeError: Cannot read property 'componentInstance' of null", - "notes": "FW-1059: DebugNode.query should query nodes in the logical tree" } }; // clang-format on