fix(ivy): set `ng-version` attribute on root component (#27175)
PR Close #27175
This commit is contained in:
parent
01917733a1
commit
bf3beb5959
|
@ -16,16 +16,16 @@ import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
|
|||
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
|
||||
import {RendererFactory2} from '../render/api';
|
||||
import {Type} from '../type';
|
||||
|
||||
import {VERSION} from '../version';
|
||||
import {assertComponentType, assertDefined} from './assert';
|
||||
import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component';
|
||||
import {getComponentDef} from './definition';
|
||||
import {NodeInjector} from './di';
|
||||
import {createLViewData, createNodeAtIndex, createTView, createViewNode, elementCreate, locateHostElement, refreshDescendantViews} from './instructions';
|
||||
import {ComponentDef, RenderFlags} from './interfaces/definition';
|
||||
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
|
||||
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||
import {FLAGS, HEADER_OFFSET, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
||||
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType} from './interfaces/node';
|
||||
import {RElement, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer';
|
||||
import {HEADER_OFFSET, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
||||
import {enterView, leaveView} from './state';
|
||||
import {defaultScheduler, getTNode} from './util';
|
||||
import {createElementRef} from './view_engine_compatibility';
|
||||
|
@ -141,6 +141,14 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||
const renderer = rendererFactory.createRenderer(hostRNode, this.componentDef);
|
||||
const rootViewInjector =
|
||||
ngModule ? createChainedInjector(injector, ngModule.injector) : injector;
|
||||
|
||||
if (rootSelectorOrNode && hostRNode) {
|
||||
ngDevMode && ngDevMode.rendererSetAttribute++;
|
||||
isProceduralRenderer(renderer) ?
|
||||
renderer.setAttribute(hostRNode, 'ng-version', VERSION.full) :
|
||||
hostRNode.setAttribute('ng-version', VERSION.full);
|
||||
}
|
||||
|
||||
// Create the root view. Uses empty TView and ContentTemplate.
|
||||
const rootView: LViewData = createLViewData(
|
||||
renderer, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags, undefined,
|
||||
|
|
|
@ -440,6 +440,9 @@
|
|||
{
|
||||
"name": "UnsubscriptionErrorImpl"
|
||||
},
|
||||
{
|
||||
"name": "VERSION"
|
||||
},
|
||||
{
|
||||
"name": "VIEWS"
|
||||
},
|
||||
|
|
|
@ -926,6 +926,9 @@
|
|||
{
|
||||
"name": "VALID_ELEMENTS"
|
||||
},
|
||||
{
|
||||
"name": "VERSION"
|
||||
},
|
||||
{
|
||||
"name": "VIEWS"
|
||||
},
|
||||
|
|
|
@ -539,32 +539,29 @@ class HiddenModule {
|
|||
});
|
||||
afterEach(() => { expect(called).toBe(true); });
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('using long form should work', async(() => {
|
||||
const platform =
|
||||
platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: doc}}]);
|
||||
it('using long form should work', async(() => {
|
||||
const platform =
|
||||
platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: doc}}]);
|
||||
|
||||
platform.bootstrapModule(AsyncServerModule)
|
||||
.then((moduleRef) => {
|
||||
const applicationRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
|
||||
return applicationRef.isStable.pipe(first((isStable: boolean) => isStable))
|
||||
.toPromise();
|
||||
})
|
||||
.then((b) => {
|
||||
expect(platform.injector.get(PlatformState).renderToString())
|
||||
.toBe(expectedOutput);
|
||||
platform.destroy();
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('using renderModule should work', async(() => {
|
||||
renderModule(AsyncServerModule, {document: doc}).then(output => {
|
||||
expect(output).toBe(expectedOutput);
|
||||
platform.bootstrapModule(AsyncServerModule)
|
||||
.then((moduleRef) => {
|
||||
const applicationRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
|
||||
return applicationRef.isStable.pipe(first((isStable: boolean) => isStable))
|
||||
.toPromise();
|
||||
})
|
||||
.then((b) => {
|
||||
expect(platform.injector.get(PlatformState).renderToString()).toBe(expectedOutput);
|
||||
platform.destroy();
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
}));
|
||||
|
||||
it('using renderModule should work', async(() => {
|
||||
renderModule(AsyncServerModule, {document: doc}).then(output => {
|
||||
expect(output).toBe(expectedOutput);
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
|
||||
it('using renderModuleFactory should work',
|
||||
async(inject([PlatformRef], (defaultPlatform: PlatformRef) => {
|
||||
|
@ -609,14 +606,13 @@ class HiddenModule {
|
|||
}));
|
||||
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('sets a prefix for the _nghost and _ngcontent attributes', async(() => {
|
||||
renderModule(ExampleStylesModule, {document: doc}).then(output => {
|
||||
expect(output).toMatch(
|
||||
/<html><head><style ng-transition="example-styles">div\[_ngcontent-sc\d+\] {color: blue; } \[_nghost-sc\d+\] { color: red; }<\/style><\/head><body><app _nghost-sc\d+="" ng-version="0.0.0-PLACEHOLDER"><div _ngcontent-sc\d+="">Works!<\/div><\/app><\/body><\/html>/);
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
it('sets a prefix for the _nghost and _ngcontent attributes', async(() => {
|
||||
renderModule(ExampleStylesModule, {document: doc}).then(output => {
|
||||
expect(output).toMatch(
|
||||
/<html><head><style ng-transition="example-styles">div\[_ngcontent-sc\d+\] {color: blue; } \[_nghost-sc\d+\] { color: red; }<\/style><\/head><body><app _nghost-sc\d+="" ng-version="0.0.0-PLACEHOLDER"><div _ngcontent-sc\d+="">Works!<\/div><\/app><\/body><\/html>/);
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('should handle false values on attributes', async(() => {
|
||||
|
@ -662,29 +658,27 @@ class HiddenModule {
|
|||
});
|
||||
}));
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('should call render hook', async(() => {
|
||||
renderModule(RenderHookModule, {document: doc}).then(output => {
|
||||
// title should be added by the render hook.
|
||||
expect(output).toBe(
|
||||
'<html><head><title>RenderHook</title></head><body>' +
|
||||
'<app ng-version="0.0.0-PLACEHOLDER">Works!</app></body></html>');
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
it('should call render hook', async(() => {
|
||||
renderModule(RenderHookModule, {document: doc}).then(output => {
|
||||
// title should be added by the render hook.
|
||||
expect(output).toBe(
|
||||
'<html><head><title>RenderHook</title></head><body>' +
|
||||
'<app ng-version="0.0.0-PLACEHOLDER">Works!</app></body></html>');
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('should call multiple render hooks', async(() => {
|
||||
const consoleSpy = spyOn(console, 'warn');
|
||||
renderModule(MultiRenderHookModule, {document: doc}).then(output => {
|
||||
// title should be added by the render hook.
|
||||
expect(output).toBe(
|
||||
'<html><head><title>RenderHook</title><meta name="description"></head>' +
|
||||
'<body><app ng-version="0.0.0-PLACEHOLDER">Works!</app></body></html>');
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
it('should call multiple render hooks', async(() => {
|
||||
const consoleSpy = spyOn(console, 'warn');
|
||||
renderModule(MultiRenderHookModule, {document: doc}).then(output => {
|
||||
// title should be added by the render hook.
|
||||
expect(output).toBe(
|
||||
'<html><head><title>RenderHook</title><meta name="description"></head>' +
|
||||
'<body><app ng-version="0.0.0-PLACEHOLDER">Works!</app></body></html>');
|
||||
expect(consoleSpy).toHaveBeenCalled();
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('http', () => {
|
||||
|
@ -856,13 +850,12 @@ class HiddenModule {
|
|||
beforeEach(() => { called = false; });
|
||||
afterEach(() => { expect(called).toBe(true); });
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('adds transfer script tag when using renderModule', async(() => {
|
||||
renderModule(TransferStoreModule, {document: '<app></app>'}).then(output => {
|
||||
expect(output).toBe(defaultExpectedOutput);
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
it('adds transfer script tag when using renderModule', async(() => {
|
||||
renderModule(TransferStoreModule, {document: '<app></app>'}).then(output => {
|
||||
expect(output).toBe(defaultExpectedOutput);
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
|
||||
it('adds transfer script tag when using renderModuleFactory',
|
||||
async(inject([PlatformRef], (defaultPlatform: PlatformRef) => {
|
||||
|
@ -876,19 +869,18 @@ class HiddenModule {
|
|||
});
|
||||
})));
|
||||
|
||||
fixmeIvy('to investigate') &&
|
||||
it('cannot break out of <script> tag in serialized output', async(() => {
|
||||
renderModule(EscapedTransferStoreModule, {
|
||||
document: '<esc-app></esc-app>'
|
||||
}).then(output => {
|
||||
expect(output).toBe(
|
||||
'<html><head></head><body><esc-app ng-version="0.0.0-PLACEHOLDER">Works!</esc-app>' +
|
||||
'<script id="transfer-state" type="application/json">' +
|
||||
'{&q;testString&q;:&q;&l;/script&g;&l;script&g;' +
|
||||
'alert(&s;Hello&a;&s; + \\&q;World\\&q;);&q;}</script></body></html>');
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
it('cannot break out of <script> tag in serialized output', async(() => {
|
||||
renderModule(EscapedTransferStoreModule, {
|
||||
document: '<esc-app></esc-app>'
|
||||
}).then(output => {
|
||||
expect(output).toBe(
|
||||
'<html><head></head><body><esc-app ng-version="0.0.0-PLACEHOLDER">Works!</esc-app>' +
|
||||
'<script id="transfer-state" type="application/json">' +
|
||||
'{&q;testString&q;:&q;&l;/script&g;&l;script&g;' +
|
||||
'alert(&s;Hello&a;&s; + \\&q;World\\&q;);&q;}</script></body></html>');
|
||||
called = true;
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
Loading…
Reference in New Issue