|
6 | 6 | * found in the LICENSE file at https://angular.dev/license |
7 | 7 | */ |
8 | 8 |
|
9 | | -import {Component, NgModule, ViewEncapsulation} from '@angular/core'; |
| 9 | +import {Component, inject, NgModule, ViewContainerRef, ViewEncapsulation} from '@angular/core'; |
10 | 10 | import {TestBed} from '@angular/core/testing'; |
11 | | -import {BrowserModule} from '../../index'; |
| 11 | +import {BrowserModule, ISOLATED_SHADOW_DOM} from '../../index'; |
12 | 12 | import {expect} from '@angular/private/testing/matchers'; |
13 | 13 | import {isNode} from '@angular/private/testing'; |
14 | 14 |
|
@@ -81,6 +81,85 @@ describe('ShadowDOM Support', () => { |
81 | 81 | expect(articleContent.assignedSlot).toBe(articleSlot); |
82 | 82 | expect(articleSubcontent.assignedSlot).toBe(articleSlot); |
83 | 83 | }); |
| 84 | + |
| 85 | + it('should inject None shared styles in web elements', () => { |
| 86 | + const comp = TestBed.createComponent(ShadowInjectedComponent); |
| 87 | + const compEl = comp.nativeElement as HTMLElement; |
| 88 | + const div = compEl.shadowRoot!.querySelector('div.green')!; |
| 89 | + // Not set before creating a sibling component |
| 90 | + expect(window.getComputedStyle(div).color).toEqual('rgb(0, 0, 0)'); |
| 91 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(1); // one <style> element |
| 92 | + // Add NoneStyleComponent |
| 93 | + const compInstance = comp.componentInstance; |
| 94 | + const viewContainerRef = compInstance.viewContainerRef; |
| 95 | + viewContainerRef.createComponent(NoneStyleComponent); |
| 96 | + expect(window.getComputedStyle(div).color).toEqual('rgb(0, 128, 0)'); // green |
| 97 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(2); // two <style> elements |
| 98 | + }); |
| 99 | + |
| 100 | + it('should inject Emulated shared styles in web elements', () => { |
| 101 | + const comp = TestBed.createComponent(ShadowInjectedComponent); |
| 102 | + const compEl = comp.nativeElement as HTMLElement; |
| 103 | + const div = compEl.shadowRoot!.querySelector('div.yellow')!; |
| 104 | + // Not set before creating a sibling component |
| 105 | + expect(window.getComputedStyle(div).color).toEqual('rgb(0, 0, 0)'); |
| 106 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(1); // one <style> element |
| 107 | + // Add EmulatedStyleComponent |
| 108 | + const compInstance = comp.componentInstance; |
| 109 | + const viewContainerRef = compInstance.viewContainerRef; |
| 110 | + viewContainerRef.createComponent(EmulatedStyleComponent); |
| 111 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(2); // two <style> elements |
| 112 | + }); |
| 113 | + |
| 114 | + describe('should not inject shared styles in shadow dom when `ISOLATED_SHADOW_DOM` is `true`', () => { |
| 115 | + beforeEach(() => { |
| 116 | + TestBed.resetTestingModule(); |
| 117 | + TestBed.configureTestingModule({ |
| 118 | + imports: [BrowserModule], |
| 119 | + declarations: [ |
| 120 | + StyledShadowComponent, |
| 121 | + NoneStyleComponent, |
| 122 | + EmulatedStyleComponent, |
| 123 | + ShadowInjectedComponent, |
| 124 | + ], |
| 125 | + providers: [ |
| 126 | + { |
| 127 | + provide: ISOLATED_SHADOW_DOM, |
| 128 | + useValue: true, |
| 129 | + }, |
| 130 | + ], |
| 131 | + }); |
| 132 | + }); |
| 133 | + |
| 134 | + it('should not inject None shared styles in web elements', () => { |
| 135 | + const comp = TestBed.createComponent(ShadowInjectedComponent); |
| 136 | + const compEl = comp.nativeElement as HTMLElement; |
| 137 | + const div = compEl.shadowRoot!.querySelector('div.green')!; |
| 138 | + // Not set before creating a sibling component |
| 139 | + expect(window.getComputedStyle(div).color).toEqual('rgb(0, 0, 0)'); |
| 140 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(1); // one <style> element |
| 141 | + // Add NoneStyleComponent |
| 142 | + const compInstance = comp.componentInstance; |
| 143 | + const viewContainerRef = compInstance.viewContainerRef; |
| 144 | + viewContainerRef.createComponent(NoneStyleComponent); |
| 145 | + expect(window.getComputedStyle(div).color).toEqual('rgb(0, 0, 0)'); |
| 146 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(1); |
| 147 | + }); |
| 148 | + |
| 149 | + it('should not inject Emulated shared styles in web elements', () => { |
| 150 | + const comp = TestBed.createComponent(ShadowInjectedComponent); |
| 151 | + const compEl = comp.nativeElement as HTMLElement; |
| 152 | + const div = compEl.shadowRoot!.querySelector('div.yellow')!; |
| 153 | + // Not set before creating a sibling component |
| 154 | + expect(window.getComputedStyle(div).color).toEqual('rgb(0, 0, 0)'); |
| 155 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(1); // one <style> element |
| 156 | + // Add EmulatedStyleComponent |
| 157 | + const compInstance = comp.componentInstance; |
| 158 | + const viewContainerRef = compInstance.viewContainerRef; |
| 159 | + viewContainerRef.createComponent(EmulatedStyleComponent); |
| 160 | + expect(compEl.shadowRoot!.querySelectorAll('style').length).toEqual(1); |
| 161 | + }); |
| 162 | + }); |
84 | 163 | }); |
85 | 164 |
|
86 | 165 | @Component({ |
@@ -117,9 +196,46 @@ class ShadowSlotComponent {} |
117 | 196 | }) |
118 | 197 | class ShadowSlotsComponent {} |
119 | 198 |
|
| 199 | +@Component({ |
| 200 | + selector: 'shadow-inj-comp', |
| 201 | + template: '<div class="green yellow"></div>', |
| 202 | + styles: [`.green { background-color: green; } .yellow { background-color: yellow; }`], |
| 203 | + encapsulation: ViewEncapsulation.ShadowDom, |
| 204 | + standalone: false, |
| 205 | +}) |
| 206 | +class ShadowInjectedComponent { |
| 207 | + viewContainerRef = inject(ViewContainerRef); |
| 208 | +} |
| 209 | + |
| 210 | +@Component({ |
| 211 | + selector: 'none-style-comp', |
| 212 | + template: '<div class="green"></div>', |
| 213 | + styles: [`.green { color: green; }`], |
| 214 | + encapsulation: ViewEncapsulation.None, |
| 215 | + standalone: false, |
| 216 | +}) |
| 217 | +class NoneStyleComponent {} |
| 218 | + |
| 219 | +@Component({ |
| 220 | + selector: 'emulated-style-comp', |
| 221 | + template: '<div class="yellow"></div>', |
| 222 | + styles: [`.yellow { color: yellow; }`], |
| 223 | + encapsulation: ViewEncapsulation.Emulated, |
| 224 | + standalone: false, |
| 225 | +}) |
| 226 | +class EmulatedStyleComponent {} |
| 227 | + |
120 | 228 | @NgModule({ |
121 | 229 | imports: [BrowserModule], |
122 | | - declarations: [ShadowComponent, ShadowSlotComponent, ShadowSlotsComponent, StyledShadowComponent], |
| 230 | + declarations: [ |
| 231 | + ShadowComponent, |
| 232 | + ShadowSlotComponent, |
| 233 | + ShadowSlotsComponent, |
| 234 | + StyledShadowComponent, |
| 235 | + NoneStyleComponent, |
| 236 | + EmulatedStyleComponent, |
| 237 | + ShadowInjectedComponent, |
| 238 | + ], |
123 | 239 | }) |
124 | 240 | class TestModule { |
125 | 241 | ngDoBootstrap() {} |
|
0 commit comments