fix(docs-infra): fix the `component-interaction` example e2e tests to run in prod mode (#39001)

Previously, the `component-interaction` docs example was configured to
run e2e tests on CI in development mode (in contrast to the default for
all docs examples, which is to run e2e tests in production mode). This
was necessary due to the following reasons:
- One of the components, `CountdownTimerComponent`, which is used by
  `CountdownLocalVarParentComponent` and
  `CountdownViewChildParentComponent`, was triggering a periodic
  asynchronous task (via `setInterval()`), which prevented the app from
  stabilizing and caused tests to fail.
- In order to prevent this from happening, the example's `AppModule` had
  special provisioning to not include the problematic components in its
  declarations when testing.
- Since this had to be determined dynamically at runtime (via inspecting
  the URL query params), the `AppModule`'s config could not be
  statically evaluated in AOT compilation.

This commit fixes the example to make it compatible with AOT compilation
and removes the custom test command from its `example-config.json`
(allowing it to be run with the default e2e test command, i.e. in
production mode).

PR Close #39001
This commit is contained in:
George Kalpakas 2020-09-25 16:31:31 +03:00 committed by Alex Rickabaugh
parent c5e178997c
commit 2b6b9c95f9
5 changed files with 27 additions and 55 deletions

View File

@ -2,11 +2,7 @@ import { browser, element, by } from 'protractor';
describe('Component Communication Cookbook Tests', () => {
// Note: '?e2e' which app can read to know it is running in protractor
// e.g. `if (!/e2e/.test(location.search)) { ...`
beforeAll(() => {
browser.get('?e2e');
});
beforeAll(() => browser.get(browser.baseUrl));
describe('Parent-to-child communication', () => {
// #docregion parent-to-child
@ -156,11 +152,11 @@ describe('Component Communication Cookbook Tests', () => {
// Can't run timer tests in protractor because
// interaction w/ zones causes all tests to freeze & timeout.
xdescribe('Parent calls child via local var', () => {
countDownTimerTests('countdown-parent-lv');
countDownTimerTests('app-countdown-parent-lv');
});
xdescribe('Parent calls ViewChild', () => {
countDownTimerTests('countdown-parent-vc');
countDownTimerTests('app-countdown-parent-vc');
});
function countDownTimerTests(parentTag: string) {
@ -168,10 +164,14 @@ describe('Component Communication Cookbook Tests', () => {
// ...
it('timer and parent seconds should match', () => {
const parent = element(by.tagName(parentTag));
const startButton = parent.element(by.tagName('button')).get(0);
const message = parent.element(by.tagName('app-countdown-timer')).getText();
browser.sleep(10); // give `seconds` a chance to catchup with `message`
const seconds = parent.element(by.className('seconds')).getText();
expect(message).toContain(seconds);
startButton.click().then(() => {
browser.sleep(10); // give `seconds` a chance to catchup with `message`
const seconds = parent.element(by.className('seconds')).getText();
expect(message).toContain(seconds);
});
});
it('should stop the countdown', () => {

View File

@ -1,13 +0,0 @@
{
"tests": [
{
"cmd": "yarn",
"args": [
"e2e",
"--protractor-config=e2e/protractor-puppeteer.conf.js",
"--no-webdriver-update",
"--port={PORT}"
]
}
]
}

View File

@ -30,22 +30,21 @@
<app-vote-taker></app-vote-taker>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>
<hr>
<div id="parent-to-child-local-var">
<app-countdown-parent-lv></app-countdown-parent-lv>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>
<hr>
<div id="parent-to-view-child">
<app-countdown-parent-vc></app-countdown-parent-vc>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>
<hr>
<div id="bidirectional-service">
<app-mission-control></app-mission-control>
</div>
<a href="#top" class="to-top">Back to Top</a>
<hr>

View File

@ -1,4 +1,4 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@ -15,10 +15,17 @@ import { VersionParentComponent } from './version-parent.component';
import { VoterComponent } from './voter.component';
import { VoteTakerComponent } from './votetaker.component';
const directives: any[] = [
@NgModule({
imports: [
BrowserModule,
],
declarations: [
AppComponent,
AstronautComponent,
CountdownLocalVarParentComponent,
CountdownTimerComponent,
CountdownViewChildParentComponent,
HeroChildComponent,
HeroParentComponent,
MissionControlComponent,
@ -27,28 +34,8 @@ const directives: any[] = [
VersionChildComponent,
VersionParentComponent,
VoterComponent,
VoteTakerComponent
];
const schemas: any[] = [];
// Include Countdown examples
// unless in e2e tests which they break.
if (!/e2e/.test(location.search)) {
console.log('adding countdown timer examples');
directives.push(CountdownLocalVarParentComponent);
directives.push(CountdownViewChildParentComponent);
} else {
// In e2e test use CUSTOM_ELEMENTS_SCHEMA to suppress unknown element errors
schemas.push(CUSTOM_ELEMENTS_SCHEMA);
}
@NgModule({
imports: [
BrowserModule
VoteTakerComponent,
],
declarations: directives,
bootstrap: [ AppComponent ],
schemas
})
export class AppModule { }

View File

@ -1,19 +1,16 @@
// #docregion
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnDestroy } from '@angular/core';
@Component({
selector: 'app-countdown-timer',
template: '<p>{{message}}</p>'
})
export class CountdownTimerComponent implements OnInit, OnDestroy {
export class CountdownTimerComponent implements OnDestroy {
intervalId = 0;
message = '';
seconds = 11;
clearTimer() { clearInterval(this.intervalId); }
ngOnInit() { this.start(); }
ngOnDestroy() { this.clearTimer(); }
start() { this.countDown(); }
@ -22,6 +19,8 @@ export class CountdownTimerComponent implements OnInit, OnDestroy {
this.message = `Holding at T-${this.seconds} seconds`;
}
private clearTimer() { clearInterval(this.intervalId); }
private countDown() {
this.clearTimer();
this.intervalId = window.setInterval(() => {