Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/universal-app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ load("//src/cdk:config.bzl", "CDK_TARGETS")
load("//src/cdk-experimental:config.bzl", "CDK_EXPERIMENTAL_TARGETS")
load("//src/material:config.bzl", "MATERIAL_TARGETS")
load("//src/material-experimental:config.bzl", "MATERIAL_EXPERIMENTAL_TARGETS")
load("//tools:defaults.bzl", "devmode_esbuild", "http_server", "ng_module", "sass_binary", "ts_library")
load("//tools:defaults.bzl", "devmode_esbuild", "http_server", "ng_e2e_test_library", "ng_module", "protractor_web_test_suite", "sass_binary", "ts_library")
load("//tools/angular:index.bzl", "LINKER_PROCESSED_FW_PACKAGES")

package(default_visibility = ["//visibility:public"])
Expand Down Expand Up @@ -127,6 +127,7 @@ http_server(
name = "server",
srcs = [
":debug_prerender_bin",
"@npm//zone.js",
],
additional_root_paths = [
"npm/node_modules",
Expand All @@ -137,3 +138,19 @@ http_server(
":styles_scss",
],
)

ng_e2e_test_library(
name = "hydration_e2e_tests_sources",
srcs = ["hydration.e2e.spec.ts"],
)

protractor_web_test_suite(
name = "hydration_e2e_tests",
configuration = ":protractor.conf.js",
on_prepare = ":start-devserver.js",
server = ":server",
tags = ["e2e"],
deps = [
":hydration_e2e_tests_sources",
],
)
33 changes: 33 additions & 0 deletions src/universal-app/hydration.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {browser, by, element, ExpectedConditions} from 'protractor';

describe('hydration e2e', () => {
beforeEach(async () => {
await browser.waitForAngularEnabled(false);
await browser.get('/');
await browser.wait(ExpectedConditions.presenceOf(element(by.css('.render-marker'))), 5000);
});

it('should enable hydration', async () => {
const hydrationState = await getHydrationState();
const logs = await browser.manage().logs().get('browser');

expect(hydrationState.hydratedComponents).toBeGreaterThan(0);
expect(logs.map(log => log.message).filter(msg => msg.includes('NG0500'))).toEqual([]);
});

it('should not skip hydration on any components', async () => {
const hydrationState = await getHydrationState();
expect(hydrationState.componentsSkippedHydration).toBe(0);
});
});

/** Gets the hydration state from the current app. */
async function getHydrationState() {
return browser.executeScript<{
hydratedComponents: number;
componentsSkippedHydration: number;
}>(() => ({
hydratedComponents: (window as any).ngDevMode.hydratedComponents,
componentsSkippedHydration: (window as any).ngDevMode.componentsSkippedHydration,
}));
}
3 changes: 3 additions & 0 deletions src/universal-app/kitchen-sink/kitchen-sink.html
Original file line number Diff line number Diff line change
Expand Up @@ -606,3 +606,6 @@ <h2>Google Map</h2>
<map-marker [position]="{lat: 12, lng: 12}"></map-marker>
</map-marker-clusterer>
</google-map>

<!-- Element used to determine when rendering is done. -->
<div class="render-marker"></div>
12 changes: 12 additions & 0 deletions src/universal-app/protractor.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
exports.config = {
useAllAngular2AppRoots: true,
allScriptsTimeout: 120000,
getPageTimeout: 120000,
jasmineNodeOpts: {
defaultTimeoutInterval: 120000,
},

// Since we want to use async/await we don't want to mix up with selenium's promise
// manager. In order to enforce this, we disable the promise manager.
SELENIUM_PROMISE_MANAGER: false,
};
21 changes: 21 additions & 0 deletions src/universal-app/start-devserver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const protractor = require('protractor');

// Note: We need to specify an explicit file extension here because otherwise
// the Bazel-patched NodeJS module resolution would resolve to the `.mjs` file
// in non-sandbox environments (as usually with Bazel and Windows).
const utils = require('@bazel/protractor/protractor-utils.js');

/**
* Called by Protractor before starting any tests. This is script is responsible for
* starting up the devserver and updating the Protractor base URL to the proper port.
*/
module.exports = async function (config) {
const {port} = await utils.runServer(config.workspace, config.server, '--port', []);
const baseUrl = `http://localhost:${port}`;
const processedConfig = await protractor.browser.getProcessedConfig();

// Update the protractor "baseUrl" to match the new random TCP port. We need random TCP ports
// because otherwise Bazel could not execute protractor tests concurrently.
protractor.browser.baseUrl = baseUrl;
processedConfig.baseUrl = baseUrl;
};