mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
test(platform-browser): verify that Angular supports bootstrapping under shadow roots
This tests bootstrapping Angular underneath a shadow root and that styles are applied and removed at the correct locations.
This commit is contained in:
parent
cdda51a3b2
commit
e453848ae6
1 changed files with 152 additions and 1 deletions
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {Component, NgModule, ViewEncapsulation} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {BrowserModule} from '../../index';
|
||||
import {BrowserModule, createApplication} from '../../index';
|
||||
import {expect} from '@angular/private/testing/matchers';
|
||||
import {isNode} from '@angular/private/testing';
|
||||
|
||||
|
|
@ -23,6 +23,10 @@ describe('ShadowDOM Support', () => {
|
|||
TestBed.configureTestingModule({imports: [TestModule]});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
for (const node of Array.from(document.body.childNodes)) node.remove();
|
||||
});
|
||||
|
||||
it('should attach and use a shadowRoot when ViewEncapsulation.ShadowDom is set', () => {
|
||||
const compEl = TestBed.createComponent(ShadowComponent).nativeElement;
|
||||
expect(compEl.shadowRoot!.textContent).toEqual('Hello World');
|
||||
|
|
@ -81,6 +85,153 @@ describe('ShadowDOM Support', () => {
|
|||
expect(articleContent.assignedSlot).toBe(articleSlot);
|
||||
expect(articleSubcontent.assignedSlot).toBe(articleSlot);
|
||||
});
|
||||
|
||||
it('should support bootstrapping under a shadow root', async () => {
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: '<div>Hello, World!</div>',
|
||||
styles: `
|
||||
div {
|
||||
color: red;
|
||||
}
|
||||
`,
|
||||
})
|
||||
class Root {}
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.attachShadow({mode: 'open'});
|
||||
const root = document.createElement('app-root');
|
||||
container.shadowRoot!.append(root);
|
||||
document.body.append(container);
|
||||
|
||||
const appRef = await createApplication();
|
||||
appRef.bootstrap(Root, root);
|
||||
|
||||
expect(getComputedStyle(root.querySelector('div')!).color).toBe('rgb(255, 0, 0)');
|
||||
|
||||
expect(document.head.innerHTML).not.toContain('<style>');
|
||||
|
||||
appRef.destroy();
|
||||
|
||||
expect(container.shadowRoot!.innerHTML).not.toContain('<style>');
|
||||
});
|
||||
|
||||
it('should support bootstrapping multiple root components under different shadow roots', async () => {
|
||||
const appRef = await createApplication();
|
||||
|
||||
{
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: '<div>Hello, World!</div>',
|
||||
styles: `
|
||||
div {
|
||||
color: red;
|
||||
}
|
||||
`,
|
||||
})
|
||||
class Root {}
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.attachShadow({mode: 'open'});
|
||||
const root = document.createElement('app-root');
|
||||
container.shadowRoot!.append(root);
|
||||
document.body.append(container);
|
||||
|
||||
appRef.bootstrap(Root, root);
|
||||
expect(getComputedStyle(root.querySelector('div')!).color).toBe('rgb(255, 0, 0)');
|
||||
}
|
||||
|
||||
{
|
||||
@Component({
|
||||
selector: 'app-root-2',
|
||||
template: '<div>Hello, World!</div>',
|
||||
styles: `
|
||||
div {
|
||||
color: lime;
|
||||
}
|
||||
`,
|
||||
})
|
||||
class Root {}
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.attachShadow({mode: 'open'});
|
||||
const root = document.createElement('app-root-2');
|
||||
container.shadowRoot!.append(root);
|
||||
document.body.append(container);
|
||||
|
||||
appRef.bootstrap(Root, root);
|
||||
expect(getComputedStyle(root.querySelector('div')!).color).toBe('rgb(0, 255, 0)');
|
||||
}
|
||||
|
||||
expect(document.head.innerHTML).not.toContain('<style>');
|
||||
|
||||
appRef.destroy();
|
||||
|
||||
const containers = Array.from(document.querySelectorAll('div'));
|
||||
const [shadowRoot1, shadowRoot2] = containers.map((container) => container.shadowRoot!);
|
||||
expect(shadowRoot1.innerHTML).not.toContain('<style>');
|
||||
expect(shadowRoot2.innerHTML).not.toContain('<style>');
|
||||
});
|
||||
|
||||
it('should not leak styles into previously used shadow roots', async () => {
|
||||
const container1 = document.createElement('div');
|
||||
container1.attachShadow({mode: 'open'});
|
||||
document.body.append(container1);
|
||||
|
||||
const container2 = document.createElement('div');
|
||||
container2.attachShadow({mode: 'open'});
|
||||
document.body.append(container2);
|
||||
|
||||
const appRef = await createApplication();
|
||||
|
||||
{
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: '<div>Hello, World!</div>',
|
||||
styles: `
|
||||
div {
|
||||
color: red;
|
||||
}
|
||||
`,
|
||||
})
|
||||
class Root {}
|
||||
|
||||
const rootEl = document.createElement('app-root');
|
||||
container1.shadowRoot!.append(rootEl);
|
||||
|
||||
const root = appRef.bootstrap(Root, rootEl);
|
||||
expect(getComputedStyle(rootEl.querySelector('div')!).color).toBe('rgb(255, 0, 0)');
|
||||
root.destroy();
|
||||
|
||||
expect(container1.shadowRoot!.innerHTML).not.toContain('<style>');
|
||||
}
|
||||
|
||||
{
|
||||
@Component({
|
||||
selector: 'app-root-2',
|
||||
template: '<div>Hello, World!</div>',
|
||||
styles: `
|
||||
div {
|
||||
color: lime;
|
||||
}
|
||||
`,
|
||||
})
|
||||
class Root2 {}
|
||||
|
||||
const root2El = document.createElement('app-root-2');
|
||||
container2.shadowRoot!.append(root2El);
|
||||
|
||||
const root = appRef.bootstrap(Root2, root2El);
|
||||
expect(getComputedStyle(root2El.querySelector('div')!).color).toBe('rgb(0, 255, 0)');
|
||||
|
||||
// Should not leak into `container1`.
|
||||
expect(container1.shadowRoot!.innerHTML).not.toContain('<style>');
|
||||
|
||||
root.destroy();
|
||||
}
|
||||
|
||||
appRef.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
@Component({
|
||||
|
|
|
|||
Loading…
Reference in a new issue