test(elements): add integration tests for Angular Elements using `ShadowDom` (#39452)

Previously, the project used for running integration tests for Angular
Elements declared a component that used `ShadowDom` for view
encopsulation, but it did not include any tests to verify that the view
was updated correctly.

This commit adds the missing tests.

PR Close #39452
This commit is contained in:
George Kalpakas 2020-11-04 20:45:33 +02:00 committed by Misko Hevery
parent 9cd2741d6c
commit c1907809a8
5 changed files with 43 additions and 22 deletions

View File

@ -1,22 +1,42 @@
import { browser, element, ExpectedConditions as EC, by } from 'protractor'; import {browser, by, element, ElementFinder, ExpectedConditions as EC} from 'protractor';
browser.waitForAngularEnabled(false); browser.waitForAngularEnabled(false);
describe('Element E2E Tests', function () { describe('Element E2E Tests', function () {
describe('Hello World Elements', () => { describe('Hello World Elements', () => {
const helloWorldEl = element(by.css('hello-world-el'));
beforeEach(() => browser.get('hello-world.html')); beforeEach(() => browser.get('hello-world.html'));
it('should display "Hello World!"', function () { describe('(with default view encapsulation)', () => {
expect(helloWorldEl.getText()).toEqual('Hello World!'); const helloWorldEl = element(by.css('hello-world-el'));
it('should display "Hello World!"', function () {
expect(helloWorldEl.getText()).toBe('Hello World!');
});
it('should display "Hello Foo!" via name attribute', function () {
const input = element(by.css('input[type=text]'));
input.sendKeys('Foo');
// Make tests less flaky on CI by waiting up to 5s for the element text to be updated.
browser.wait(EC.textToBePresentInElement(helloWorldEl, 'Hello Foo!'), 5000);
});
}); });
it('should display "Hello Foo!" via name attribute', function () { describe('(with `ShadowDom` view encapsulation)', () => {
const input = element(by.css('input[type=text]')); const helloWorldShadowEl = element(by.css('hello-world-shadow-el'));
input.sendKeys('Foo'); const getShadowDomText = (el: ElementFinder) =>
browser.executeScript('return arguments[0].shadowRoot.textContent', el);
// Make tests less flaky on CI by waiting up to 5s for the element text to be updated. it('should display "Hello World!"', function () {
browser.wait(EC.textToBePresentInElement(helloWorldEl, 'Hello Foo!'), 5000); expect(getShadowDomText(helloWorldShadowEl)).toBe('Hello World!');
});
it('should display "Hello Foo!" via name attribute', function () {
const input = element(by.css('input[type=text]'));
input.sendKeys('Foo');
// Make tests less flaky on CI by waiting up to 5s for the element text to be updated.
browser.wait(async () => await getShadowDomText(helloWorldShadowEl) === 'Hello Foo!', 5000);
});
}); });
}); });
}); });

View File

@ -11,7 +11,7 @@ import {HelloWorldComponent, HelloWorldShadowComponent, TestCardComponent} from
imports: [BrowserModule], imports: [BrowserModule],
}) })
export class AppModule { export class AppModule {
constructor(private injector: Injector) { constructor(injector: Injector) {
customElements.define('hello-world-el', createCustomElement(HelloWorldComponent, {injector})); customElements.define('hello-world-el', createCustomElement(HelloWorldComponent, {injector}));
customElements.define( customElements.define(
'hello-world-shadow-el', createCustomElement(HelloWorldShadowComponent, {injector})); 'hello-world-shadow-el', createCustomElement(HelloWorldShadowComponent, {injector}));

View File

@ -2,7 +2,7 @@ import {Component, Input, ViewEncapsulation} from '@angular/core';
@Component({ @Component({
selector: 'hello-world-el', selector: 'hello-world-el',
template: `Hello {{name}}!`, template: 'Hello {{name}}!',
}) })
export class HelloWorldComponent { export class HelloWorldComponent {
@Input() name: string = 'World'; @Input() name: string = 'World';
@ -10,14 +10,13 @@ export class HelloWorldComponent {
@Component({ @Component({
selector: 'hello-world-shadow-el', selector: 'hello-world-shadow-el',
template: `Hello {{name}}!`, template: 'Hello {{name}}!',
encapsulation: ViewEncapsulation.ShadowDom encapsulation: ViewEncapsulation.ShadowDom,
}) })
export class HelloWorldShadowComponent { export class HelloWorldShadowComponent {
@Input() name: string = 'World'; @Input() name: string = 'World';
} }
@Component({ @Component({
selector: 'test-card', selector: 'test-card',
template: ` template: `
@ -29,7 +28,6 @@ export class HelloWorldShadowComponent {
<slot name="card-footer"></slot> <slot name="card-footer"></slot>
</footer>`, </footer>`,
encapsulation: ViewEncapsulation.ShadowDom, encapsulation: ViewEncapsulation.ShadowDom,
styles: []
}) })
export class TestCardComponent { export class TestCardComponent {
} }

View File

@ -10,8 +10,8 @@
<body> <body>
<input type="text"> <input type="text">
<hello-world-el></hello-world-el> <hello-world-el></hello-world-el>
<hello-world-shadow-el></hello-world-shadow-el>
<script src="dist/bundle.js"></script> <script src="dist/bundle.js"></script>
</body> </body>
</html> </html>

View File

@ -3,8 +3,11 @@ import {AppModuleNgFactory} from './app.ngfactory';
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory, {ngZone: 'noop'}); platformBrowser().bootstrapModuleFactory(AppModuleNgFactory, {ngZone: 'noop'});
const input = document.querySelector('input'); const input = document.querySelector('input')!;
const helloWorld = document.querySelector('hello-world-el'); const helloWorld = document.querySelector('hello-world-el')!;
if(input && helloWorld){ const helloWorldShadow = document.querySelector('hello-world-shadow-el')!;
input.addEventListener('input', () => helloWorld.setAttribute('name', input.value));
} input.addEventListener('input', () => {
helloWorld.setAttribute('name', input.value);
helloWorldShadow.setAttribute('name', input.value);
});