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:
parent
c5e178997c
commit
2b6b9c95f9
|
@ -2,11 +2,7 @@ import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Component Communication Cookbook Tests', () => {
|
describe('Component Communication Cookbook Tests', () => {
|
||||||
|
|
||||||
// Note: '?e2e' which app can read to know it is running in protractor
|
beforeAll(() => browser.get(browser.baseUrl));
|
||||||
// e.g. `if (!/e2e/.test(location.search)) { ...`
|
|
||||||
beforeAll(() => {
|
|
||||||
browser.get('?e2e');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Parent-to-child communication', () => {
|
describe('Parent-to-child communication', () => {
|
||||||
// #docregion parent-to-child
|
// #docregion parent-to-child
|
||||||
|
@ -156,11 +152,11 @@ describe('Component Communication Cookbook Tests', () => {
|
||||||
// Can't run timer tests in protractor because
|
// Can't run timer tests in protractor because
|
||||||
// interaction w/ zones causes all tests to freeze & timeout.
|
// interaction w/ zones causes all tests to freeze & timeout.
|
||||||
xdescribe('Parent calls child via local var', () => {
|
xdescribe('Parent calls child via local var', () => {
|
||||||
countDownTimerTests('countdown-parent-lv');
|
countDownTimerTests('app-countdown-parent-lv');
|
||||||
});
|
});
|
||||||
|
|
||||||
xdescribe('Parent calls ViewChild', () => {
|
xdescribe('Parent calls ViewChild', () => {
|
||||||
countDownTimerTests('countdown-parent-vc');
|
countDownTimerTests('app-countdown-parent-vc');
|
||||||
});
|
});
|
||||||
|
|
||||||
function countDownTimerTests(parentTag: string) {
|
function countDownTimerTests(parentTag: string) {
|
||||||
|
@ -168,11 +164,15 @@ describe('Component Communication Cookbook Tests', () => {
|
||||||
// ...
|
// ...
|
||||||
it('timer and parent seconds should match', () => {
|
it('timer and parent seconds should match', () => {
|
||||||
const parent = element(by.tagName(parentTag));
|
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();
|
const message = parent.element(by.tagName('app-countdown-timer')).getText();
|
||||||
|
|
||||||
|
startButton.click().then(() => {
|
||||||
browser.sleep(10); // give `seconds` a chance to catchup with `message`
|
browser.sleep(10); // give `seconds` a chance to catchup with `message`
|
||||||
const seconds = parent.element(by.className('seconds')).getText();
|
const seconds = parent.element(by.className('seconds')).getText();
|
||||||
expect(message).toContain(seconds);
|
expect(message).toContain(seconds);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should stop the countdown', () => {
|
it('should stop the countdown', () => {
|
||||||
const parent = element(by.tagName(parentTag));
|
const parent = element(by.tagName(parentTag));
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"cmd": "yarn",
|
|
||||||
"args": [
|
|
||||||
"e2e",
|
|
||||||
"--protractor-config=e2e/protractor-puppeteer.conf.js",
|
|
||||||
"--no-webdriver-update",
|
|
||||||
"--port={PORT}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -30,22 +30,21 @@
|
||||||
<app-vote-taker></app-vote-taker>
|
<app-vote-taker></app-vote-taker>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
<hr>
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
<div id="parent-to-child-local-var">
|
<div id="parent-to-child-local-var">
|
||||||
<app-countdown-parent-lv></app-countdown-parent-lv>
|
<app-countdown-parent-lv></app-countdown-parent-lv>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
<hr>
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
<div id="parent-to-view-child">
|
<div id="parent-to-view-child">
|
||||||
<app-countdown-parent-vc></app-countdown-parent-vc>
|
<app-countdown-parent-vc></app-countdown-parent-vc>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
<hr>
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
<div id="bidirectional-service">
|
<div id="bidirectional-service">
|
||||||
<app-mission-control></app-mission-control>
|
<app-mission-control></app-mission-control>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="to-top">Back to Top</a>
|
<a href="#top" class="to-top">Back to Top</a>
|
||||||
<hr>
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
@ -15,10 +15,17 @@ import { VersionParentComponent } from './version-parent.component';
|
||||||
import { VoterComponent } from './voter.component';
|
import { VoterComponent } from './voter.component';
|
||||||
import { VoteTakerComponent } from './votetaker.component';
|
import { VoteTakerComponent } from './votetaker.component';
|
||||||
|
|
||||||
const directives: any[] = [
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
AstronautComponent,
|
AstronautComponent,
|
||||||
|
CountdownLocalVarParentComponent,
|
||||||
CountdownTimerComponent,
|
CountdownTimerComponent,
|
||||||
|
CountdownViewChildParentComponent,
|
||||||
HeroChildComponent,
|
HeroChildComponent,
|
||||||
HeroParentComponent,
|
HeroParentComponent,
|
||||||
MissionControlComponent,
|
MissionControlComponent,
|
||||||
|
@ -27,28 +34,8 @@ const directives: any[] = [
|
||||||
VersionChildComponent,
|
VersionChildComponent,
|
||||||
VersionParentComponent,
|
VersionParentComponent,
|
||||||
VoterComponent,
|
VoterComponent,
|
||||||
VoteTakerComponent
|
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
|
|
||||||
],
|
],
|
||||||
declarations: directives,
|
|
||||||
bootstrap: [ AppComponent ],
|
bootstrap: [ AppComponent ],
|
||||||
schemas
|
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-countdown-timer',
|
selector: 'app-countdown-timer',
|
||||||
template: '<p>{{message}}</p>'
|
template: '<p>{{message}}</p>'
|
||||||
})
|
})
|
||||||
export class CountdownTimerComponent implements OnInit, OnDestroy {
|
export class CountdownTimerComponent implements OnDestroy {
|
||||||
|
|
||||||
intervalId = 0;
|
intervalId = 0;
|
||||||
message = '';
|
message = '';
|
||||||
seconds = 11;
|
seconds = 11;
|
||||||
|
|
||||||
clearTimer() { clearInterval(this.intervalId); }
|
|
||||||
|
|
||||||
ngOnInit() { this.start(); }
|
|
||||||
ngOnDestroy() { this.clearTimer(); }
|
ngOnDestroy() { this.clearTimer(); }
|
||||||
|
|
||||||
start() { this.countDown(); }
|
start() { this.countDown(); }
|
||||||
|
@ -22,6 +19,8 @@ export class CountdownTimerComponent implements OnInit, OnDestroy {
|
||||||
this.message = `Holding at T-${this.seconds} seconds`;
|
this.message = `Holding at T-${this.seconds} seconds`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private clearTimer() { clearInterval(this.intervalId); }
|
||||||
|
|
||||||
private countDown() {
|
private countDown() {
|
||||||
this.clearTimer();
|
this.clearTimer();
|
||||||
this.intervalId = window.setInterval(() => {
|
this.intervalId = window.setInterval(() => {
|
||||||
|
|
Loading…
Reference in New Issue