Skip to content

Commit 17c291b

Browse files
authored
build: add automated test for hydration (#28395)
Sets up some tests to verify that we don't regress on our hydration support.
1 parent d3e8a28 commit 17c291b

File tree

5 files changed

+87
-1
lines changed

5 files changed

+87
-1
lines changed

src/universal-app/BUILD.bazel

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ load("//src/cdk:config.bzl", "CDK_TARGETS")
44
load("//src/cdk-experimental:config.bzl", "CDK_EXPERIMENTAL_TARGETS")
55
load("//src/material:config.bzl", "MATERIAL_TARGETS")
66
load("//src/material-experimental:config.bzl", "MATERIAL_EXPERIMENTAL_TARGETS")
7-
load("//tools:defaults.bzl", "devmode_esbuild", "http_server", "ng_module", "sass_binary", "ts_library")
7+
load("//tools:defaults.bzl", "devmode_esbuild", "http_server", "ng_e2e_test_library", "ng_module", "protractor_web_test_suite", "sass_binary", "ts_library")
88
load("//tools/angular:index.bzl", "LINKER_PROCESSED_FW_PACKAGES")
99

1010
package(default_visibility = ["//visibility:public"])
@@ -127,6 +127,7 @@ http_server(
127127
name = "server",
128128
srcs = [
129129
":debug_prerender_bin",
130+
"@npm//zone.js",
130131
],
131132
additional_root_paths = [
132133
"npm/node_modules",
@@ -137,3 +138,19 @@ http_server(
137138
":styles_scss",
138139
],
139140
)
141+
142+
ng_e2e_test_library(
143+
name = "hydration_e2e_tests_sources",
144+
srcs = ["hydration.e2e.spec.ts"],
145+
)
146+
147+
protractor_web_test_suite(
148+
name = "hydration_e2e_tests",
149+
configuration = ":protractor.conf.js",
150+
on_prepare = ":start-devserver.js",
151+
server = ":server",
152+
tags = ["e2e"],
153+
deps = [
154+
":hydration_e2e_tests_sources",
155+
],
156+
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import {browser, by, element, ExpectedConditions} from 'protractor';
2+
3+
describe('hydration e2e', () => {
4+
beforeEach(async () => {
5+
await browser.waitForAngularEnabled(false);
6+
await browser.get('/');
7+
await browser.wait(ExpectedConditions.presenceOf(element(by.css('.render-marker'))), 5000);
8+
});
9+
10+
it('should enable hydration', async () => {
11+
const hydrationState = await getHydrationState();
12+
const logs = await browser.manage().logs().get('browser');
13+
14+
expect(hydrationState.hydratedComponents).toBeGreaterThan(0);
15+
expect(logs.map(log => log.message).filter(msg => msg.includes('NG0500'))).toEqual([]);
16+
});
17+
18+
it('should not skip hydration on any components', async () => {
19+
const hydrationState = await getHydrationState();
20+
expect(hydrationState.componentsSkippedHydration).toBe(0);
21+
});
22+
});
23+
24+
/** Gets the hydration state from the current app. */
25+
async function getHydrationState() {
26+
return browser.executeScript<{
27+
hydratedComponents: number;
28+
componentsSkippedHydration: number;
29+
}>(() => ({
30+
hydratedComponents: (window as any).ngDevMode.hydratedComponents,
31+
componentsSkippedHydration: (window as any).ngDevMode.componentsSkippedHydration,
32+
}));
33+
}

src/universal-app/kitchen-sink/kitchen-sink.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,6 @@ <h2>Google Map</h2>
606606
<map-marker [position]="{lat: 12, lng: 12}"></map-marker>
607607
</map-marker-clusterer>
608608
</google-map>
609+
610+
<!-- Element used to determine when rendering is done. -->
611+
<div class="render-marker"></div>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
exports.config = {
2+
useAllAngular2AppRoots: true,
3+
allScriptsTimeout: 120000,
4+
getPageTimeout: 120000,
5+
jasmineNodeOpts: {
6+
defaultTimeoutInterval: 120000,
7+
},
8+
9+
// Since we want to use async/await we don't want to mix up with selenium's promise
10+
// manager. In order to enforce this, we disable the promise manager.
11+
SELENIUM_PROMISE_MANAGER: false,
12+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const protractor = require('protractor');
2+
3+
// Note: We need to specify an explicit file extension here because otherwise
4+
// the Bazel-patched NodeJS module resolution would resolve to the `.mjs` file
5+
// in non-sandbox environments (as usually with Bazel and Windows).
6+
const utils = require('@bazel/protractor/protractor-utils.js');
7+
8+
/**
9+
* Called by Protractor before starting any tests. This is script is responsible for
10+
* starting up the devserver and updating the Protractor base URL to the proper port.
11+
*/
12+
module.exports = async function (config) {
13+
const {port} = await utils.runServer(config.workspace, config.server, '--port', []);
14+
const baseUrl = `http://localhost:${port}`;
15+
const processedConfig = await protractor.browser.getProcessedConfig();
16+
17+
// Update the protractor "baseUrl" to match the new random TCP port. We need random TCP ports
18+
// because otherwise Bazel could not execute protractor tests concurrently.
19+
protractor.browser.baseUrl = baseUrl;
20+
processedConfig.baseUrl = baseUrl;
21+
};

0 commit comments

Comments
 (0)