diff --git a/goldens/size-tracking/integration-payloads.json b/goldens/size-tracking/integration-payloads.json index ad2750482a..08bbaafdd7 100644 --- a/goldens/size-tracking/integration-payloads.json +++ b/goldens/size-tracking/integration-payloads.json @@ -3,7 +3,7 @@ "master": { "uncompressed": { "runtime-es2015": 1170, - "main-es2015": 138718, + "main-es2015": 138189, "polyfills-es2015": 36964 } } @@ -30,7 +30,7 @@ "master": { "uncompressed": { "runtime-es2015": 1190, - "main-es2015": 137087, + "main-es2015": 136546, "polyfills-es2015": 37641 } } diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index c630f82a3c..f5db218fac 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -262,10 +262,9 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme } get name(): string { - const context = getLContext(this.nativeNode)!; - const lView = context ? context.lView : null; - - if (lView !== null) { + const context = getLContext(this.nativeNode); + if (context !== null) { + const lView = context.lView; const tData = lView[TVIEW].data; const tNode = tData[context.nodeIndex] as TNode; return tNode.value!; @@ -287,13 +286,12 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme * - attribute bindings (e.g. `[attr.role]="menu"`) */ get properties(): {[key: string]: any;} { - const context = getLContext(this.nativeNode)!; - const lView = context ? context.lView : null; - - if (lView === null) { + const context = getLContext(this.nativeNode); + if (context === null) { return {}; } + const lView = context.lView; const tData = lView[TVIEW].data; const tNode = tData[context.nodeIndex] as TNode; @@ -314,13 +312,12 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme return attributes; } - const context = getLContext(element)!; - const lView = context ? context.lView : null; - - if (lView === null) { + const context = getLContext(element); + if (context === null) { return {}; } + const lView = context.lView; const tNodeAttrs = (lView[TVIEW].data[context.nodeIndex] as TNode).attrs; const lowercaseTNodeAttrs: string[] = []; @@ -505,12 +502,11 @@ function _queryAllR3( function _queryAllR3( parentElement: DebugElement, predicate: Predicate|Predicate, matches: DebugElement[]|DebugNode[], elementsOnly: boolean) { - const context = getLContext(parentElement.nativeNode)!; - const lView = context ? context.lView : null; - if (lView !== null) { - const parentTNode = lView[TVIEW].data[context.nodeIndex] as TNode; + const context = getLContext(parentElement.nativeNode); + if (context !== null) { + const parentTNode = context.lView[TVIEW].data[context.nodeIndex] as TNode; _queryNodeChildrenR3( - parentTNode, lView, predicate, matches, elementsOnly, parentElement.nativeNode); + parentTNode, context.lView, predicate, matches, elementsOnly, parentElement.nativeNode); } else { // If the context is null, then `parentElement` was either created with Renderer2 or native DOM // APIs. diff --git a/packages/core/src/render3/context_discovery.ts b/packages/core/src/render3/context_discovery.ts index e57b980f0c..43f4207eb7 100644 --- a/packages/core/src/render3/context_discovery.ts +++ b/packages/core/src/render3/context_discovery.ts @@ -8,15 +8,12 @@ import '../util/ng_dev_mode'; import {assertDefined, assertDomNode} from '../util/assert'; -import {EMPTY_ARRAY} from '../util/empty'; -import {assertLView} from './assert'; +import {EMPTY_ARRAY} from '../util/empty'; import {LContext} from './interfaces/context'; -import {getLViewById} from './interfaces/lview_tracking'; import {TNode, TNodeFlags} from './interfaces/node'; import {RElement, RNode} from './interfaces/renderer_dom'; -import {isLView} from './interfaces/type_checks'; -import {CONTEXT, HEADER_OFFSET, HOST, ID, LView, TVIEW} from './interfaces/view'; +import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view'; import {getComponentLViewByIndex, unwrapRNode} from './util/view_utils'; @@ -46,7 +43,7 @@ export function getLContext(target: any): LContext|null { if (mpValue) { // only when it's an array is it considered an LView instance // ... otherwise it's an already constructed LContext instance - if (isLView(mpValue)) { + if (Array.isArray(mpValue)) { const lView: LView = mpValue!; let nodeIndex: number; let component: any = undefined; @@ -108,7 +105,12 @@ export function getLContext(target: any): LContext|null { while (parent = parent.parentNode) { const parentContext = readPatchedData(parent); if (parentContext) { - const lView = Array.isArray(parentContext) ? parentContext as LView : parentContext.lView; + let lView: LView|null; + if (Array.isArray(parentContext)) { + lView = parentContext as LView; + } else { + lView = parentContext.lView; + } // the edge of the app was also reached here through another means // (maybe because the DOM was changed manually). @@ -134,7 +136,14 @@ export function getLContext(target: any): LContext|null { * Creates an empty instance of a `LContext` context */ function createLContext(lView: LView, nodeIndex: number, native: RNode): LContext { - return new LContext(lView[ID], nodeIndex, native); + return { + lView, + nodeIndex, + native, + component: undefined, + directives: undefined, + localRefs: undefined, + }; } /** @@ -144,24 +153,21 @@ function createLContext(lView: LView, nodeIndex: number, native: RNode): LContex * @returns The component's view */ export function getComponentViewByInstance(componentInstance: {}): LView { - let patchedData = readPatchedData(componentInstance); - let lView: LView; + let lView = readPatchedData(componentInstance); + let view: LView; - if (isLView(patchedData)) { - const contextLView: LView = patchedData; - const nodeIndex = findViaComponent(contextLView, componentInstance); - lView = getComponentLViewByIndex(nodeIndex, contextLView); - const context = createLContext(contextLView, nodeIndex, lView[HOST] as RElement); + if (Array.isArray(lView)) { + const nodeIndex = findViaComponent(lView, componentInstance); + view = getComponentLViewByIndex(nodeIndex, lView); + const context = createLContext(lView, nodeIndex, view[HOST] as RElement); context.component = componentInstance; attachPatchData(componentInstance, context); attachPatchData(context.native, context); } else { - const context = patchedData as unknown as LContext; - const contextLView = context.lView!; - ngDevMode && assertLView(contextLView); - lView = getComponentLViewByIndex(context.nodeIndex, contextLView); + const context = lView as any as LContext; + view = getComponentLViewByIndex(context.nodeIndex, context.lView); } - return lView; + return view; } /** @@ -175,10 +181,7 @@ const MONKEY_PATCH_KEY_NAME = '__ngContext__'; */ export function attachPatchData(target: any, data: LView|LContext) { ngDevMode && assertDefined(target, 'Target expected'); - // Only attach the ID of the view in order to avoid memory leaks (see #41047). We only do this - // for `LView`, because we have control over when an `LView` is created and destroyed, whereas - // we can't know when to remove an `LContext`. - target[MONKEY_PATCH_KEY_NAME] = isLView(data) ? data[ID] : data; + target[MONKEY_PATCH_KEY_NAME] = data; } /** @@ -187,14 +190,13 @@ export function attachPatchData(target: any, data: LView|LContext) { */ export function readPatchedData(target: any): LView|LContext|null { ngDevMode && assertDefined(target, 'Target expected'); - const data = target[MONKEY_PATCH_KEY_NAME]; - return (typeof data === 'number') ? getLViewById(data) : data || null; + return target[MONKEY_PATCH_KEY_NAME] || null; } export function readPatchedLView(target: any): LView|null { const value = readPatchedData(target); if (value) { - return isLView(value) ? value : value.lView; + return Array.isArray(value) ? value : (value as LContext).lView; } return null; } diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index 7a7551f27d..1fd21dfbfd 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -25,7 +25,7 @@ import {LQueries, TQueries} from '../interfaces/query'; import {Renderer3, RendererFactory3} from '../interfaces/renderer'; import {RComment, RElement, RNode} from '../interfaces/renderer_dom'; import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling'; -import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DebugNode, DECLARATION_VIEW, DestroyHookData, FLAGS, HEADER_OFFSET, HookData, HOST, HostBindingOpCodes, ID, INJECTOR, LContainerDebug as ILContainerDebug, LView, LViewDebug as ILViewDebug, LViewDebugRange, LViewDebugRangeContent, LViewFlags, NEXT, NodeInjectorDebug, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, T_HOST, TData, TView as ITView, TVIEW, TView, TViewType, TViewTypeAsString} from '../interfaces/view'; +import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DebugNode, DECLARATION_VIEW, DestroyHookData, FLAGS, HEADER_OFFSET, HookData, HOST, HostBindingOpCodes, INJECTOR, LContainerDebug as ILContainerDebug, LView, LViewDebug as ILViewDebug, LViewDebugRange, LViewDebugRangeContent, LViewFlags, NEXT, NodeInjectorDebug, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, T_HOST, TData, TView as ITView, TVIEW, TView, TViewType, TViewTypeAsString} from '../interfaces/view'; import {attachDebugObject} from '../util/debug_utils'; import {getParentInjectorIndex, getParentInjectorView} from '../util/injector_utils'; import {unwrapRNode} from '../util/view_utils'; @@ -513,9 +513,6 @@ export class LViewDebug implements ILViewDebug { get tHost(): ITNode|null { return this._raw_lView[T_HOST]; } - get id(): number { - return this._raw_lView[ID]; - } get decls(): LViewDebugRange { return toLViewRange(this.tView, this._raw_lView, HEADER_OFFSET, this.tView.bindingStartIndex); diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 47590176da..34d6ef6daf 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -28,13 +28,12 @@ import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags} fr import {CONTAINER_HEADER_OFFSET, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS} from '../interfaces/container'; import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, HostBindingsFunction, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from '../interfaces/definition'; import {NodeInjectorFactory} from '../interfaces/injector'; -import {registerLView} from '../interfaces/lview_tracking'; import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliases, PropertyAliasValue, TAttributes, TConstantsOrFactory, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode} from '../interfaces/node'; import {isProceduralRenderer, Renderer3, RendererFactory3} from '../interfaces/renderer'; import {RComment, RElement, RNode, RText} from '../interfaces/renderer_dom'; import {SanitizerFn} from '../interfaces/sanitization'; import {isComponentDef, isComponentHost, isContentQueryHost, isRootView} from '../interfaces/type_checks'; -import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HostBindingOpCodes, ID, InitPhaseState, INJECTOR, LView, LViewFlags, NEXT, PARENT, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, T_HOST, TData, TRANSPLANTED_VIEWS_TO_REFRESH, TVIEW, TView, TViewType} from '../interfaces/view'; +import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HostBindingOpCodes, InitPhaseState, INJECTOR, LView, LViewFlags, NEXT, PARENT, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, T_HOST, TData, TRANSPLANTED_VIEWS_TO_REFRESH, TVIEW, TView, TViewType} from '../interfaces/view'; import {assertPureTNodeType, assertTNodeType} from '../node_assert'; import {updateTextNode} from '../node_manipulation'; import {isInlineTemplate, isNodeMatchingSelectorList} from '../node_selector_matcher'; @@ -144,7 +143,6 @@ export function createLView( lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null!; lView[INJECTOR as any] = injector || parentLView && parentLView[INJECTOR] || null; lView[T_HOST] = tHostNode; - lView[ID] = registerLView(lView); ngDevMode && assertEqual( tView.type == TViewType.Embedded ? parentLView !== null : true, true, @@ -1908,12 +1906,9 @@ export function scheduleTick(rootContext: RootContext, flags: RootContextFlags) export function tickRootContext(rootContext: RootContext) { for (let i = 0; i < rootContext.components.length; i++) { const rootComponent = rootContext.components[i]; - const lView = readPatchedLView(rootComponent); - // We might not have an `LView` if the component was destroyed. - if (lView !== null) { - const tView = lView[TVIEW]; - renderComponentOrTemplate(tView, lView, tView.template, rootComponent); - } + const lView = readPatchedLView(rootComponent)!; + const tView = lView[TVIEW]; + renderComponentOrTemplate(tView, lView, tView.template, rootComponent); } } diff --git a/packages/core/src/render3/interfaces/context.ts b/packages/core/src/render3/interfaces/context.ts index e097719190..6f78e26891 100644 --- a/packages/core/src/render3/interfaces/context.ts +++ b/packages/core/src/render3/interfaces/context.ts @@ -7,7 +7,6 @@ */ -import {getLViewById} from './lview_tracking'; import {RNode} from './renderer_dom'; import {LView} from './view'; @@ -22,41 +21,35 @@ import {LView} from './view'; * function. The component, element and each directive instance will share the same instance * of the context. */ -export class LContext { +export interface LContext { + /** + * The component's parent view data. + */ + lView: LView; + + /** + * The index instance of the node. + */ + nodeIndex: number; + + /** + * The instance of the DOM node that is attached to the lNode. + */ + native: RNode; + /** * The instance of the Component node. */ - public component: {}|null|undefined; + component: {}|null|undefined; /** * The list of active directives that exist on this element. */ - public directives: any[]|null|undefined; + directives: any[]|null|undefined; /** - * The map of local references (local reference name => element or directive instance) that - * exist on this element. + * The map of local references (local reference name => element or directive instance) that exist + * on this element. */ - public localRefs: {[key: string]: any}|null|undefined; - - /** Component's parent view data. */ - get lView(): LView|null { - return getLViewById(this.lViewId); - } - - constructor( - /** - * ID of the component's parent view data. - */ - private lViewId: number, - - /** - * The index instance of the node. - */ - public nodeIndex: number, - - /** - * The instance of the DOM node that is attached to the lNode. - */ - public native: RNode) {} + localRefs: {[key: string]: any}|null|undefined; } diff --git a/packages/core/src/render3/interfaces/lview_tracking.ts b/packages/core/src/render3/interfaces/lview_tracking.ts deleted file mode 100644 index 7c965ff98a..0000000000 --- a/packages/core/src/render3/interfaces/lview_tracking.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright Google LLC 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 {assertNumber} from '../../util/assert'; -import {ID, LView} from './view'; - -// Keeps track of the currently-active LViews. -const TRACKED_LVIEWS = new Map(); - -// Used for generating unique IDs for LViews. -let uniqueIdCounter = 0; - -/** Starts tracking an LView and returns a unique ID that can be used for future lookups. */ -export function registerLView(lView: LView): number { - const id = uniqueIdCounter++; - TRACKED_LVIEWS.set(id, lView); - return id; -} - -/** Gets an LView by its unique ID. */ -export function getLViewById(id: number): LView|null { - ngDevMode && assertNumber(id, 'ID used for LView lookup must be a number'); - return TRACKED_LVIEWS.get(id) || null; -} - -/** Stops tracking an LView. */ -export function unregisterLView(lView: LView): void { - ngDevMode && assertNumber(lView[ID], 'Cannot stop tracking an LView that does not have an ID'); - TRACKED_LVIEWS.delete(lView[ID]); -} diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 34d12482f4..af0202bcf6 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -47,7 +47,6 @@ export const DECLARATION_COMPONENT_VIEW = 16; export const DECLARATION_LCONTAINER = 17; export const PREORDER_HOOK_FLAGS = 18; export const QUERIES = 19; -export const ID = 20; /** * Size of LView's header. Necessary to adjust for it when setting slots. * @@ -55,7 +54,7 @@ export const ID = 20; * instruction index into `LView` index. All other indexes should be in the `LView` index space and * there should be no need to refer to `HEADER_OFFSET` anywhere else. */ -export const HEADER_OFFSET = 21; +export const HEADER_OFFSET = 20; // This interface replaces the real LView interface if it is an arg or a @@ -327,9 +326,6 @@ export interface LView extends Array { * are not `Dirty`/`CheckAlways`. */ [TRANSPLANTED_VIEWS_TO_REFRESH]: number; - - /** Unique ID of the view. Used for `__ngContext__` lookups in the `LView` registry. */ - [ID]: number; } /** Flags associated with an LView (saved in LView[FLAGS]) */ diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 35ce766098..801957fe21 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -19,7 +19,6 @@ import {icuContainerIterate} from './i18n/i18n_tree_shaking'; import {CONTAINER_HEADER_OFFSET, HAS_TRANSPLANTED_VIEWS, LContainer, MOVED_VIEWS, NATIVE, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; import {ComponentDef} from './interfaces/definition'; import {NodeInjectorFactory} from './interfaces/injector'; -import {unregisterLView} from './interfaces/lview_tracking'; import {TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; import {isProceduralRenderer, ProceduralRenderer3, Renderer3, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; @@ -396,7 +395,6 @@ export function destroyLView(tView: TView, lView: LView) { } destroyViewTree(lView); - unregisterLView(lView); } } diff --git a/packages/core/src/render3/util/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts index 37d60efe8f..430df1bf2d 100644 --- a/packages/core/src/render3/util/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -11,7 +11,7 @@ import {Injector} from '../../di/injector'; import {ViewEncapsulation} from '../../metadata/view'; import {assertEqual} from '../../util/assert'; import {assertLView} from '../assert'; -import {discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext, readPatchedLView} from '../context_discovery'; +import {discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext} from '../context_discovery'; import {getComponentDef, getDirectiveDef} from '../definition'; import {NodeInjector} from '../di'; import {buildDebugNode} from '../instructions/lview_debug'; @@ -20,7 +20,6 @@ import {DirectiveDef} from '../interfaces/definition'; import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node'; import {isLView} from '../interfaces/type_checks'; import {CLEANUP, CONTEXT, DebugNode, FLAGS, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../interfaces/view'; - import {stringifyForError} from './stringify_utils'; import {getLViewParent, getRootContext} from './view_traversal_utils'; import {getTNode, unwrapRNode} from './view_utils'; @@ -53,16 +52,12 @@ import {getTNode, unwrapRNode} from './view_utils'; * @globalApi ng */ export function getComponent(element: Element): T|null { - ngDevMode && assertDomElement(element); + assertDomElement(element); const context = getLContext(element); if (context === null) return null; if (context.component === undefined) { - const lView = context.lView; - if (lView === null) { - return null; - } - context.component = getComponentAtNodeIndex(context.nodeIndex, lView); + context.component = getComponentAtNodeIndex(context.nodeIndex, context.lView); } return context.component as T; @@ -83,9 +78,8 @@ export function getComponent(element: Element): T|null { */ export function getContext(element: Element): T|null { assertDomElement(element); - const context = getLContext(element)!; - const lView = context ? context.lView : null; - return lView === null ? null : lView[CONTEXT] as T; + const context = getLContext(element); + return context === null ? null : context.lView[CONTEXT] as T; } /** @@ -104,11 +98,12 @@ export function getContext(element: Element): T|null { * @globalApi ng */ export function getOwningComponent(elementOrDir: Element|{}): T|null { - const context = getLContext(elementOrDir)!; - let lView = context ? context.lView : null; - if (lView === null) return null; + const context = getLContext(elementOrDir); + if (context === null) return null; + let lView = context.lView; let parent: LView|null; + ngDevMode && assertLView(lView); while (lView[TVIEW].type === TViewType.Embedded && (parent = getLViewParent(lView)!)) { lView = parent; } @@ -127,8 +122,7 @@ export function getOwningComponent(elementOrDir: Element|{}): T|null { * @globalApi ng */ export function getRootComponents(elementOrDir: Element|{}): {}[] { - const lView = readPatchedLView(elementOrDir); - return lView !== null ? [...getRootContext(lView).components] : []; + return [...getRootContext(elementOrDir).components]; } /** @@ -142,12 +136,11 @@ export function getRootComponents(elementOrDir: Element|{}): {}[] { * @globalApi ng */ export function getInjector(elementOrDir: Element|{}): Injector { - const context = getLContext(elementOrDir)!; - const lView = context ? context.lView : null; - if (lView === null) return Injector.NULL; + const context = getLContext(elementOrDir); + if (context === null) return Injector.NULL; - const tNode = lView[TVIEW].data[context.nodeIndex] as TElementNode; - return new NodeInjector(tNode, lView); + const tNode = context.lView[TVIEW].data[context.nodeIndex] as TElementNode; + return new NodeInjector(tNode, context.lView); } /** @@ -156,9 +149,9 @@ export function getInjector(elementOrDir: Element|{}): Injector { * @param element Element for which the injection tokens should be retrieved. */ export function getInjectionTokens(element: Element): any[] { - const context = getLContext(element)!; - const lView = context ? context.lView : null; - if (lView === null) return []; + const context = getLContext(element); + if (context === null) return []; + const lView = context.lView; const tView = lView[TVIEW]; const tNode = tView.data[context.nodeIndex] as TNode; const providerTokens: any[] = []; @@ -207,12 +200,12 @@ export function getDirectives(node: Node): {}[] { return []; } - const context = getLContext(node)!; - const lView = context ? context.lView : null; - if (lView === null) { + const context = getLContext(node); + if (context === null) { return []; } + const lView = context.lView; const tView = lView[TVIEW]; const nodeIndex = context.nodeIndex; if (!tView?.data[nodeIndex]) { @@ -304,11 +297,7 @@ export function getLocalRefs(target: {}): {[key: string]: any} { if (context === null) return {}; if (context.localRefs === undefined) { - const lView = context.lView; - if (lView === null) { - return {}; - } - context.localRefs = discoverLocalRefs(lView, context.nodeIndex); + context.localRefs = discoverLocalRefs(context.lView, context.nodeIndex); } return context.localRefs || {}; @@ -394,11 +383,11 @@ export interface Listener { * @globalApi ng */ export function getListeners(element: Element): Listener[] { - ngDevMode && assertDomElement(element); + assertDomElement(element); const lContext = getLContext(element); - const lView = lContext === null ? null : lContext.lView; - if (lView === null) return []; + if (lContext === null) return []; + const lView = lContext.lView; const tView = lView[TVIEW]; const lCleanup = lView[CLEANUP]; const tCleanup = tView.cleanup; @@ -452,13 +441,12 @@ export function getDebugNode(element: Element): DebugNode|null { throw new Error('Expecting instance of DOM Element'); } - const lContext = getLContext(element)!; - const lView = lContext ? lContext.lView : null; - - if (lView === null) { + const lContext = getLContext(element); + if (lContext === null) { return null; } + const lView = lContext.lView; const nodeIndex = lContext.nodeIndex; if (nodeIndex !== -1) { const valueInLView = lView[nodeIndex]; @@ -485,8 +473,7 @@ export function getDebugNode(element: Element): DebugNode|null { export function getComponentLView(target: any): LView { const lContext = getLContext(target)!; const nodeIndx = lContext.nodeIndex; - const lView = lContext.lView!; - ngDevMode && assertLView(lView); + const lView = lContext.lView; const componentLView = lView[nodeIndx]; ngDevMode && assertLView(componentLView); return componentLView; diff --git a/packages/core/test/acceptance/component_spec.ts b/packages/core/test/acceptance/component_spec.ts index 5b4c2b23ae..31994aadac 100644 --- a/packages/core/test/acceptance/component_spec.ts +++ b/packages/core/test/acceptance/component_spec.ts @@ -141,47 +141,6 @@ describe('component', () => { expect(fixture.nativeElement.textContent.trim()).toBe('hello'); }); - onlyInIvy('ViewEngine has a specific error for this while Ivy does not') - .it('should not throw when calling `detectChanges` on the ChangeDetectorRef of a destroyed view', - () => { - @Component({template: 'hello'}) - class HelloComponent { - } - - // TODO: This module is only used to declare the `entryComponets` since - // `configureTestingModule` doesn't support it. The module can be removed - // once ViewEngine is removed. - @NgModule({ - declarations: [HelloComponent], - exports: [HelloComponent], - entryComponents: [HelloComponent] - }) - class HelloModule { - } - - @Component({template: `
`}) - class App { - @ViewChild('insertionPoint', {read: ViewContainerRef}) - viewContainerRef!: ViewContainerRef; - constructor(public componentFactoryResolver: ComponentFactoryResolver) {} - } - - TestBed.configureTestingModule({declarations: [App], imports: [HelloModule]}); - const fixture = TestBed.createComponent(App); - fixture.detectChanges(); - - const instance = fixture.componentInstance; - const factory = - instance.componentFactoryResolver.resolveComponentFactory(HelloComponent); - const componentRef = instance.viewContainerRef.createComponent(factory); - fixture.detectChanges(); - - expect(() => { - componentRef.destroy(); - componentRef.changeDetectorRef.detectChanges(); - }).not.toThrow(); - }); - // TODO: add tests with Native once tests run in real browser (domino doesn't support shadow root) describe('encapsulation', () => { @Component({ diff --git a/packages/core/test/acceptance/debug_spec.ts b/packages/core/test/acceptance/debug_spec.ts index c12985b8ab..436d134d8b 100644 --- a/packages/core/test/acceptance/debug_spec.ts +++ b/packages/core/test/acceptance/debug_spec.ts @@ -27,7 +27,7 @@ onlyInIvy('Ivy specific').describe('Debug Representation', () => { const fixture = TestBed.createComponent(MyComponent); fixture.detectChanges(); - const hostView = getLContext(fixture.componentInstance)!.lView!.debug!; + const hostView = getLContext(fixture.componentInstance)!.lView.debug!; expect(hostView.hostHTML).toEqual(null); const myCompView = hostView.childViews[0] as LViewDebug; expect(myCompView.hostHTML).toContain('
Hello World
'); @@ -47,7 +47,7 @@ onlyInIvy('Ivy specific').describe('Debug Representation', () => { const fixture = TestBed.createComponent(MyComponent); fixture.detectChanges(); - const hostView = getLContext(fixture.componentInstance)!.lView!.debug!; + const hostView = getLContext(fixture.componentInstance)!.lView.debug!; const myComponentView = hostView.childViews[0] as LViewDebug; expect(myComponentView.decls).toEqual({ start: HEADER_OFFSET, diff --git a/packages/core/test/acceptance/discover_utils_spec.ts b/packages/core/test/acceptance/discover_utils_spec.ts index 05a583b3a4..a1d589eabe 100644 --- a/packages/core/test/acceptance/discover_utils_spec.ts +++ b/packages/core/test/acceptance/discover_utils_spec.ts @@ -69,19 +69,16 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { @Component({ selector: 'my-app', template: ` - {{text}} + {{text}}
- +

- Bold ` }) class MyApp { text: string = 'INIT'; - spanVisible = true; - conditionalChildVisible = true; @Input('a') b = 2; @Output('c') d = new EventEmitter(); constructor() { @@ -108,15 +105,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getComponent(child[0])).toEqual(childComponent[0]); expect(getComponent(child[1])).toEqual(childComponent[1]); }); - it('should not throw when called on a destroyed node', () => { - expect(getComponent(span[0])).toEqual(null); - expect(getComponent(child[2])).toEqual(childComponent[2]); - fixture.componentInstance.spanVisible = false; - fixture.componentInstance.conditionalChildVisible = false; - fixture.detectChanges(); - expect(getComponent(span[0])).toEqual(null); - expect(getComponent(child[2])).toEqual(childComponent[2]); - }); }); describe('getComponentLView', () => { @@ -143,12 +131,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getContext<{$implicit: boolean}>(child[2])!.$implicit).toEqual(true); expect(getContext(p[0])).toEqual(childComponent[0]); }); - it('should return null for destroyed node', () => { - expect(getContext(span[0])).toBeTruthy(); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getContext(span[0])).toBeNull(); - }); }); describe('getHostElement', () => { @@ -164,12 +146,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { it('should throw on unknown target', () => { expect(() => getHostElement({})).toThrowError(); // }); - it('should return element for destroyed node', () => { - expect(getHostElement(span[0])).toEqual(span[0]); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getHostElement(span[0])).toEqual(span[0]); - }); }); describe('getInjector', () => { @@ -187,12 +163,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getInjector(dirA[0]).get(String)).toEqual('Module'); expect(getInjector(dirA[1]).get(String)).toEqual('Child'); }); - it('should retrieve injector from destroyed node', () => { - expect(getInjector(span[0])).toBeTruthy(); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getInjector(span[0])).toBeTruthy(); - }); }); describe('getDirectives', () => { @@ -205,12 +175,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getDirectives(div[0])).toEqual([dirA[0]]); expect(getDirectives(child[1])).toEqual([dirA[1]]); }); - it('should return empty array for destroyed node', () => { - expect(getDirectives(span[0])).toEqual([]); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getDirectives(span[0])).toEqual([]); - }); }); describe('getOwningComponent', () => { @@ -238,12 +202,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getOwningComponent(dirA[0])).toEqual(myApp); expect(getOwningComponent(dirA[1])).toEqual(myApp); }); - it('should return null for destroyed node', () => { - expect(getOwningComponent(span[0])).toEqual(myApp); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getOwningComponent(span[0])).toEqual(null); - }); }); describe('getLocalRefs', () => { @@ -261,13 +219,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getLocalRefs(child[1])).toEqual({child: childComponent[1]}); expect(getLocalRefs(dirA[1])).toEqual({child: childComponent[1]}); }); - - it('should retrieve from a destroyed node', () => { - expect(getLocalRefs(span[0])).toEqual({}); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getLocalRefs(span[0])).toEqual({}); - }); }); describe('getRootComponents', () => { @@ -283,12 +234,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getRootComponents(div[0])).toEqual(rootComponents); expect(getRootComponents(p[0])).toEqual(rootComponents); }); - it('should return an empty array for a destroyed node', () => { - expect(getRootComponents(span[0])).toEqual([myApp]); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getRootComponents(span[0])).toEqual([]); - }); }); describe('getListeners', () => { @@ -306,12 +251,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { listeners[0].callback('CLICKED'); expect(log).toEqual(['CLICKED']); }); - it('should return no listeners for destroyed node', () => { - expect(getListeners(span[0]).length).toEqual(1); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getListeners(span[0]).length).toEqual(0); - }); }); describe('getInjectionTokens', () => { @@ -320,12 +259,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getInjectionTokens(child[0])).toEqual([String, Child]); expect(getInjectionTokens(child[1])).toEqual([String, Child, DirectiveA]); }); - it('should retrieve tokens from destroyed node', () => { - expect(getInjectionTokens(span[0])).toEqual([]); - fixture.componentInstance.spanVisible = false; - fixture.detectChanges(); - expect(getInjectionTokens(span[0])).toEqual([]); - }); }); describe('markDirty', () => { diff --git a/packages/core/test/acceptance/ngdevmode_debug_spec.ts b/packages/core/test/acceptance/ngdevmode_debug_spec.ts index f3db593b68..64763f7650 100644 --- a/packages/core/test/acceptance/ngdevmode_debug_spec.ts +++ b/packages/core/test/acceptance/ngdevmode_debug_spec.ts @@ -32,7 +32,7 @@ onlyInIvy('Debug information exist in ivy only').describe('ngDevMode debug', () TestBed.configureTestingModule({declarations: [MyApp], imports: [CommonModule]}); const fixture = TestBed.createComponent(MyApp); - const rootLView = getLContext(fixture.nativeElement)!.lView!; + const rootLView = getLContext(fixture.nativeElement)!.lView; expect(rootLView.constructor.name).toEqual('LRootView'); const componentLView = getComponentLView(fixture.componentInstance); @@ -41,7 +41,7 @@ onlyInIvy('Debug information exist in ivy only').describe('ngDevMode debug', () const element: HTMLElement = fixture.nativeElement; fixture.detectChanges(); const li = element.querySelector('li')!; - const embeddedLView = getLContext(li)!.lView!; + const embeddedLView = getLContext(li)!.lView; expect(embeddedLView.constructor.name).toEqual('LEmbeddedView_MyApp_li_1'); }); }); diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index 5b040b0822..dd29afd07a 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -47,9 +47,6 @@ { "name": "SimpleChange" }, - { - "name": "TRACKED_LVIEWS" - }, { "name": "TriggerComponent" }, @@ -257,9 +254,6 @@ { "name": "isInlineTemplate" }, - { - "name": "isLView" - }, { "name": "isNodeMatchingSelector" }, @@ -359,9 +353,6 @@ { "name": "setUpAttributes" }, - { - "name": "uniqueIdCounter" - }, { "name": "updateTransplantedViewCount" }, diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index 3bd0484344..b89832be26 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -548,9 +548,6 @@ { "name": "THROW_IF_NOT_FOUND" }, - { - "name": "TRACKED_LVIEWS" - }, { "name": "TRANSITION_ID" }, @@ -1571,9 +1568,6 @@ { "name": "u" }, - { - "name": "uniqueIdCounter" - }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/forms_reactive/forms_e2e_spec.ts b/packages/core/test/bundling/forms_reactive/forms_e2e_spec.ts index 5efe851e89..65ee1ee746 100644 --- a/packages/core/test/bundling/forms_reactive/forms_e2e_spec.ts +++ b/packages/core/test/bundling/forms_reactive/forms_e2e_spec.ts @@ -7,6 +7,7 @@ */ import '@angular/compiler'; +import {ɵwhenRendered as whenRendered} from '@angular/core'; import {withBody} from '@angular/private/testing'; import * as path from 'path'; @@ -17,8 +18,8 @@ describe('functional test for reactive forms', () => { BUNDLES.forEach((bundle) => { describe(`using ${bundle} bundle`, () => { it('should render template form', withBody('', async () => { - const {whenRendered, bootstrapApp} = require(path.join(PACKAGE, bundle)); - await bootstrapApp(); + require(path.join(PACKAGE, bundle)); + await (window as any).waitForApp; // Reactive forms const reactiveFormsComponent = (window as any).reactiveFormsComponent; diff --git a/packages/core/test/bundling/forms_reactive/index.ts b/packages/core/test/bundling/forms_reactive/index.ts index 441b97afb8..b44c4f410b 100644 --- a/packages/core/test/bundling/forms_reactive/index.ts +++ b/packages/core/test/bundling/forms_reactive/index.ts @@ -5,7 +5,7 @@ * 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, NgModule, ɵNgModuleFactory as NgModuleFactory, ɵwhenRendered as whenRendered} from '@angular/core'; +import {Component, NgModule, ɵNgModuleFactory as NgModuleFactory} from '@angular/core'; import {FormArray, FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; import {BrowserModule, platformBrowser} from '@angular/platform-browser'; @@ -93,15 +93,5 @@ class FormsExampleModule { } } -function bootstrapApp() { - return platformBrowser().bootstrapModuleFactory( - new NgModuleFactory(FormsExampleModule), {ngZone: 'noop'}); -} - -// This bundle includes `@angular/core` within it which means that the test asserting -// against it will load a different core bundle. These symbols are exposed so that they -// can interact with the correct `@angular/core` instance. -module.exports = { - whenRendered, - bootstrapApp -}; +(window as any).waitForApp = platformBrowser().bootstrapModuleFactory( + new NgModuleFactory(FormsExampleModule), {ngZone: 'noop'}); diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index 76743abf90..df9a8e4ae4 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -536,9 +536,6 @@ { "name": "THROW_IF_NOT_FOUND" }, - { - "name": "TRACKED_LVIEWS" - }, { "name": "TRANSITION_ID" }, @@ -1544,9 +1541,6 @@ { "name": "u" }, - { - "name": "uniqueIdCounter" - }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/forms_template_driven/forms_e2e_spec.ts b/packages/core/test/bundling/forms_template_driven/forms_e2e_spec.ts index 3cbb8b2a97..fb67ed4908 100644 --- a/packages/core/test/bundling/forms_template_driven/forms_e2e_spec.ts +++ b/packages/core/test/bundling/forms_template_driven/forms_e2e_spec.ts @@ -7,6 +7,7 @@ */ import '@angular/compiler'; +import {ɵwhenRendered as whenRendered} from '@angular/core'; import {withBody} from '@angular/private/testing'; import * as path from 'path'; @@ -17,8 +18,8 @@ describe('functional test for forms', () => { BUNDLES.forEach((bundle) => { describe(`using ${bundle} bundle`, () => { it('should render template form', withBody('', async () => { - const {bootstrapApp, whenRendered} = require(path.join(PACKAGE, bundle)); - await bootstrapApp(); + require(path.join(PACKAGE, bundle)); + await (window as any).waitForApp; // Template forms const templateFormsComponent = (window as any).templateFormsComponent; diff --git a/packages/core/test/bundling/forms_template_driven/index.ts b/packages/core/test/bundling/forms_template_driven/index.ts index ac81bc9e23..fb03c5c0c5 100644 --- a/packages/core/test/bundling/forms_template_driven/index.ts +++ b/packages/core/test/bundling/forms_template_driven/index.ts @@ -5,7 +5,7 @@ * 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, NgModule, ɵNgModuleFactory as NgModuleFactory, ɵwhenRendered as whenRendered} from '@angular/core'; +import {Component, NgModule, ɵNgModuleFactory as NgModuleFactory} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {BrowserModule, platformBrowser} from '@angular/platform-browser'; @@ -70,15 +70,5 @@ class FormsExampleModule { } } -function bootstrapApp() { - return platformBrowser().bootstrapModuleFactory( - new NgModuleFactory(FormsExampleModule), {ngZone: 'noop'}); -} - -// This bundle includes `@angular/core` within it which means that the test asserting -// against it will load a different core bundle. These symbols are exposed so that they -// can interact with the correct `@angular/core` instance. -module.exports = { - whenRendered, - bootstrapApp -}; +(window as any).waitForApp = platformBrowser().bootstrapModuleFactory( + new NgModuleFactory(FormsExampleModule), {ngZone: 'noop'}); diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index 99bd5d32ec..9f68ceb496 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -41,9 +41,6 @@ { "name": "SimpleChange" }, - { - "name": "TRACKED_LVIEWS" - }, { "name": "ViewEncapsulation" }, @@ -176,9 +173,6 @@ { "name": "isInCheckNoChangesMode" }, - { - "name": "isLView" - }, { "name": "isProceduralRenderer" }, @@ -242,9 +236,6 @@ { "name": "setSelectedIndex" }, - { - "name": "uniqueIdCounter" - }, { "name": "updateTransplantedViewCount" }, diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index d84e3b0b76..2f236a71e8 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -785,9 +785,6 @@ { "name": "TQuery_" }, - { - "name": "TRACKED_LVIEWS" - }, { "name": "TRANSITION_ID" }, @@ -2018,9 +2015,6 @@ { "name": "u" }, - { - "name": "uniqueIdCounter" - }, { "name": "unwrapElementRef" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 80bf8cb991..057cd33ab4 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -32,9 +32,6 @@ { "name": "IterableDiffers" }, - { - "name": "LContext" - }, { "name": "NG_COMP_DEF" }, @@ -113,9 +110,6 @@ { "name": "SkipSelf" }, - { - "name": "TRACKED_LVIEWS" - }, { "name": "TemplateRef" }, @@ -386,9 +380,6 @@ { "name": "getLView" }, - { - "name": "getLViewById" - }, { "name": "getLViewParent" }, @@ -749,9 +740,6 @@ { "name": "trackByIdentity" }, - { - "name": "uniqueIdCounter" - }, { "name": "unwrapRNode" }, diff --git a/packages/core/test/bundling/todo/index.ts b/packages/core/test/bundling/todo/index.ts index de6dc37dbe..c9efb5b83b 100644 --- a/packages/core/test/bundling/todo/index.ts +++ b/packages/core/test/bundling/todo/index.ts @@ -9,7 +9,7 @@ import '@angular/core/test/bundling/util/src/reflect_metadata'; import {CommonModule} from '@angular/common'; -import {Component, Injectable, NgModule, ViewEncapsulation, ɵmarkDirty as markDirty, ɵrenderComponent as renderComponent, ɵwhenRendered as whenRendered} from '@angular/core'; +import {Component, Injectable, NgModule, ViewEncapsulation, ɵmarkDirty as markDirty, ɵrenderComponent as renderComponent} from '@angular/core'; class Todo { editing: boolean; @@ -133,9 +133,7 @@ class TodoStore { class ToDoAppComponent { newTodoText = ''; - constructor(public todoStore: TodoStore) { - (window as any).todoAppComponent = this; - } + constructor(public todoStore: TodoStore) {} cancelEditingTodo(todo: Todo) { todo.editing = false; @@ -202,8 +200,3 @@ class ToDoAppModule { } renderComponent(ToDoAppComponent); - -// This bundle includes `@angular/core` within it which means that the test asserting -// against it will load a different core bundle. These symbols are exposed so that they -// can interact with the correct `@angular/core` instance. -module.exports = {whenRendered}; diff --git a/packages/core/test/bundling/todo/todo_e2e_spec.ts b/packages/core/test/bundling/todo/todo_e2e_spec.ts index be682aa0f2..b3506d457b 100644 --- a/packages/core/test/bundling/todo/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo/todo_e2e_spec.ts @@ -7,9 +7,14 @@ */ import '@angular/compiler'; +import {ɵwhenRendered as whenRendered} from '@angular/core'; +import {getComponent} from '@angular/core/src/render3'; import {withBody} from '@angular/private/testing'; import * as path from 'path'; +const UTF8 = { + encoding: 'utf-8' +}; const PACKAGE = 'angular/packages/core/test/bundling/todo'; const BUNDLES = ['bundle.js', 'bundle.min_debug.js', 'bundle.min.js']; @@ -17,12 +22,13 @@ describe('functional test for todo', () => { BUNDLES.forEach(bundle => { describe(bundle, () => { it('should render todo', withBody('', async () => { - const {whenRendered} = require(path.join(PACKAGE, bundle)); + require(path.join(PACKAGE, bundle)); + const toDoAppComponent = getComponent(document.querySelector('todo-app')!); expect(document.body.textContent).toContain('todos'); expect(document.body.textContent).toContain('Demonstrate Components'); expect(document.body.textContent).toContain('4 items left'); document.querySelector('button')!.click(); - await whenRendered((window as any).todoAppComponent); + await whenRendered(toDoAppComponent); expect(document.body.textContent).toContain('3 items left'); })); }); diff --git a/packages/core/test/bundling/todo_i18n/index.ts b/packages/core/test/bundling/todo_i18n/index.ts index b20a3532b5..0025af70e5 100644 --- a/packages/core/test/bundling/todo_i18n/index.ts +++ b/packages/core/test/bundling/todo_i18n/index.ts @@ -8,7 +8,7 @@ import '@angular/core/test/bundling/util/src/reflect_metadata'; import './translations'; import {CommonModule} from '@angular/common'; -import {Component, Injectable, NgModule, ViewEncapsulation, ɵmarkDirty as markDirty, ɵrenderComponent as renderComponent, ɵwhenRendered as whenRendered} from '@angular/core'; +import {Component, Injectable, NgModule, ViewEncapsulation, ɵmarkDirty as markDirty, ɵrenderComponent as renderComponent} from '@angular/core'; class Todo { editing: boolean; @@ -127,9 +127,7 @@ class TodoStore { class ToDoAppComponent { newTodoText = ''; - constructor(public todoStore: TodoStore) { - (window as any).todoAppComponent = this; - } + constructor(public todoStore: TodoStore) {} cancelEditingTodo(todo: Todo) { todo.editing = false; @@ -196,8 +194,3 @@ class ToDoAppModule { } renderComponent(ToDoAppComponent); - -// This bundle includes `@angular/core` within it which means that the test asserting -// against it will load a different core bundle. These symbols are exposed so that they -// can interact with the correct `@angular/core` instance. -module.exports = {whenRendered}; diff --git a/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts b/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts index 5979f08c69..9e55a6df77 100644 --- a/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts @@ -8,6 +8,8 @@ import '@angular/localize/init'; import '@angular/compiler'; +import {ɵwhenRendered as whenRendered} from '@angular/core'; +import {getComponent} from '@angular/core/src/render3'; import {clearTranslations} from '@angular/localize'; import {withBody} from '@angular/private/testing'; import * as path from 'path'; @@ -20,7 +22,8 @@ describe('functional test for todo i18n', () => { describe(bundle, () => { it('should render todo i18n', withBody('', async () => { clearTranslations(); - const {whenRendered} = require(path.join(PACKAGE, bundle)); + require(path.join(PACKAGE, bundle)); + const toDoAppComponent = getComponent(document.querySelector('todo-app')!); expect(document.body.textContent).toContain('liste de tâches'); expect(document.body.textContent).toContain('Démontrer les components'); expect(document.body.textContent).toContain('Démontrer NgModules'); @@ -28,7 +31,7 @@ describe('functional test for todo i18n', () => { expect(document.querySelector('.new-todo')!.getAttribute('placeholder')) .toEqual(`Qu'y a-t-il à faire ?`); document.querySelector('button')!.click(); - await whenRendered((window as any).todoAppComponent); + await whenRendered(toDoAppComponent); expect(document.body.textContent).toContain('3 tâches restantes'); })); }); diff --git a/packages/core/test/bundling/todo_r2/index.ts b/packages/core/test/bundling/todo_r2/index.ts index 2c1860b4a7..bd8b360f86 100644 --- a/packages/core/test/bundling/todo_r2/index.ts +++ b/packages/core/test/bundling/todo_r2/index.ts @@ -9,7 +9,7 @@ import '@angular/core/test/bundling/util/src/reflect_metadata'; import {CommonModule} from '@angular/common'; -import {Component, Injectable, NgModule, ɵNgModuleFactory as NgModuleFactory, ɵwhenRendered as whenRendered} from '@angular/core'; +import {Component, Injectable, NgModule, ɵNgModuleFactory as NgModuleFactory} from '@angular/core'; import {BrowserModule, platformBrowser} from '@angular/platform-browser'; class Todo { @@ -195,15 +195,5 @@ class ToDoAppModule { } } -function bootstrapApp() { - return platformBrowser().bootstrapModuleFactory( - new NgModuleFactory(ToDoAppModule), {ngZone: 'noop'}); -} - -// This bundle includes `@angular/core` within it which means that the test asserting -// against it will load a different core bundle. These symbols are exposed so that they -// can interact with the correct `@angular/core` instance. -module.exports = { - whenRendered, - bootstrapApp -}; +(window as any).waitForApp = + platformBrowser().bootstrapModuleFactory(new NgModuleFactory(ToDoAppModule), {ngZone: 'noop'}); diff --git a/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts b/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts index 98781a6407..7fb449cd96 100644 --- a/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts @@ -7,9 +7,13 @@ */ import '@angular/compiler'; +import {ɵwhenRendered as whenRendered} from '@angular/core'; import {withBody} from '@angular/private/testing'; import * as path from 'path'; +const UTF8 = { + encoding: 'utf-8' +}; const PACKAGE = 'angular/packages/core/test/bundling/todo_r2'; const BUNDLES = ['bundle.js', 'bundle.min_debug.js', 'bundle.min.js']; @@ -18,8 +22,8 @@ describe('functional test for todo', () => { describe(bundle, () => { it('should place styles on the elements within the component', withBody('', async () => { - const {bootstrapApp, whenRendered} = require(path.join(PACKAGE, bundle)); - await bootstrapApp(); + require(path.join(PACKAGE, bundle)); + await (window as any).waitForApp; const toDoAppComponent = (window as any).toDoAppComponent; await whenRendered(toDoAppComponent); diff --git a/packages/core/test/render3/i18n/i18n_parse_spec.ts b/packages/core/test/render3/i18n/i18n_parse_spec.ts index 6408a30495..7608ac69aa 100644 --- a/packages/core/test/render3/i18n/i18n_parse_spec.ts +++ b/packages/core/test/render3/i18n/i18n_parse_spec.ts @@ -40,16 +40,16 @@ describe('i18n_parse', () => { // TData | LView // ---------------------------+------------------------------- // ----- DECL ----- - // 21: TI18n | + // 20: TI18n | // ----- VARS ----- - // 22: Binding for ICU | + // 21: Binding for ICU | // ----- EXPANDO ----- - // 23: null | #text(before|) - // 24: TIcu | - // 25: null | currently selected ICU case - // 26: null | #text(caseA) - // 27: null | #text(otherCase) - // 28: null | #text(|after) + // 22: null | #text(before|) + // 23: TIcu | + // 24: null | currently selected ICU case + // 25: null | #text(caseA) + // 26: null | #text(otherCase) + // 27: null | #text(|after) const tI18n = toT18n(`before|{ �0�, select, A {caseA} @@ -153,21 +153,21 @@ describe('i18n_parse', () => { // TData | LView // ---------------------------+------------------------------- // ----- DECL ----- - // 21: TI18n | + // 20: TI18n | // ----- VARS ----- - // 22: Binding for parent ICU | + // 21: Binding for parent ICU | + // 22: Binding for child ICU | // 23: Binding for child ICU | - // 24: Binding for child ICU | // ----- EXPANDO ----- - // 25: TIcu (parent) | - // 26: null | currently selected ICU case - // 27: null | #text( parentA ) - // 28: TIcu (child) | - // 29: null | currently selected ICU case - // 30: null | #text(nested0) - // 31: null | #text({{�2�}}) - // 32: null | #text( ) - // 33: null | #text( parentOther ) + // 24: TIcu (parent) | + // 25: null | currently selected ICU case + // 26: null | #text( parentA ) + // 27: TIcu (child) | + // 28: null | currently selected ICU case + // 29: null | #text(nested0) + // 30: null | #text({{�2�}}) + // 31: null | #text( ) + // 32: null | #text( parentOther ) const tI18n = toT18n(`{ �0�, select, A {parentA {�1�, select, 0 {nested0} other {�2�}}!} diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index 56784af808..fdd830d44b 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -13,7 +13,7 @@ import {AttributeMarker, ɵɵadvance, ɵɵattribute, ɵɵdefineComponent, ɵɵde import {ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵprojection, ɵɵprojectionDef, ɵɵtemplate, ɵɵtext} from '../../src/render3/instructions/all'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {domRendererFactory3, Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer'; -import {CONTEXT, HEADER_OFFSET, ID, LView} from '../../src/render3/interfaces/view'; +import {CONTEXT, HEADER_OFFSET} from '../../src/render3/interfaces/view'; import {ɵɵsanitizeUrl} from '../../src/sanitization/sanitization'; import {Sanitizer} from '../../src/sanitization/sanitizer'; import {SecurityContext} from '../../src/sanitization/security'; @@ -399,17 +399,19 @@ describe('element discovery', () => { const section = fixture.hostElement.querySelector('section')!; const sectionContext = getLContext(section)!; + const sectionLView = sectionContext.lView!; expect(sectionContext.nodeIndex).toEqual(HEADER_OFFSET); - expect(sectionContext.lView!.length).toBeGreaterThan(HEADER_OFFSET); + expect(sectionLView.length).toBeGreaterThan(HEADER_OFFSET); expect(sectionContext.native).toBe(section); const div = fixture.hostElement.querySelector('div')!; const divContext = getLContext(div)!; + const divLView = divContext.lView!; expect(divContext.nodeIndex).toEqual(HEADER_OFFSET + 1); - expect(divContext.lView!.length).toBeGreaterThan(HEADER_OFFSET); + expect(divLView.length).toBeGreaterThan(HEADER_OFFSET); expect(divContext.native).toBe(div); - expect(divContext.lView).toBe(sectionContext.lView); + expect(divLView).toBe(sectionLView); }); it('should cache the element context on a element was pre-emptively monkey-patched', () => { @@ -736,7 +738,7 @@ describe('element discovery', () => { const div1 = hostElm.querySelector('div:first-child')! as any; const div2 = hostElm.querySelector('div:last-child')! as any; const context = getLContext(hostElm)!; - const componentView = context.lView![context.nodeIndex]; + const componentView = context.lView[context.nodeIndex]; expect(componentView).toContain(myDir1Instance); expect(componentView).toContain(myDir2Instance); @@ -915,7 +917,7 @@ describe('element discovery', () => { const context = getLContext(child)!; expect(readPatchedData(child)).toBeTruthy(); - const componentData = context.lView![context.nodeIndex]; + const componentData = context.lView[context.nodeIndex]; const component = componentData[CONTEXT]; expect(component instanceof ChildComp).toBeTruthy(); expect(readPatchedData(component)).toBe(context.lView);