Skip to content

build: fix e2e rate limit failures #13376

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 1, 2018
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
29 changes: 16 additions & 13 deletions src/e2e-app/tsconfig-build.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,27 @@
"moduleResolution": "node",
"noEmitOnError": true,
"noImplicitAny": true,
"rootDir": ".",
"outDir": ".",
"rootDirs": [
"../..",
"./"
],
"outDir": "../../dist/",
"sourceMap": true,
"target": "es5",
"typeRoots": [
"../../node_modules/@types/!(node)"
],
"baseUrl": ".",
"paths": {
"@angular/cdk/*": ["./cdk/*"],
"@angular/material": ["./material"],
"@angular/material/*": ["./material/*"],
"@angular/material-experimental/*": ["./material-experimental/*"],
"@angular/material-experimental": ["./material-experimental/"],
"@angular/cdk-experimental/*": ["./cdk-experimental/*"],
"@angular/cdk-experimental": ["./cdk-experimental/"],
"@angular/material-moment-adapter": ["./material-moment-adapter"],
"@angular/material-examples": ["./material-examples"]
"@angular/cdk/*": ["../../dist/releases/cdk/*"],
"@angular/material": ["../../dist/releases/material"],
"@angular/material/*": ["../../dist/releases/material/*"],
"@angular/material-experimental/*": ["../../dist/releases/material-experimental/*"],
"@angular/material-experimental": ["../../dist/releases/material-experimental/"],
"@angular/cdk-experimental/*": ["../../dist/releases/cdk-experimental/*"],
"@angular/cdk-experimental": ["../../dist/releases/cdk-experimental/"],
"@angular/material-moment-adapter": ["../../dist/releases/material-moment-adapter"],
"@angular/material-examples": ["../../dist/releases/material-examples"]
}
},
"files": [
Expand All @@ -42,7 +45,7 @@
"./system-config.ts"
],
"angularCompilerOptions": {
"skipMetadataEmit": true,
"fullTemplateTypeCheck": true
"fullTemplateTypeCheck": true,
"enableResourceInlining": true
}
}
62 changes: 33 additions & 29 deletions tools/gulp/tasks/e2e.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import {task} from 'gulp';
import {join} from 'path';
import {ngcBuildTask, copyTask, execNodeTask, serverTask} from '../util/task_helpers';
import {copySync} from 'fs-extra';
import {buildConfig, sequenceTask, triggerLivereload, watchFiles} from 'material2-build-tools';
import {join} from 'path';
import {copyTask, execNodeTask, ngcBuildTask, serverTask} from '../util/task_helpers';

// There are no type definitions available for these imports.
const gulpConnect = require('gulp-connect');

const {outputDir, packagesDir, projectDir} = buildConfig;

/** Path to the directory where all releases are created. */
const releasesDir = join(outputDir, 'releases');

const appDir = join(packagesDir, 'e2e-app');
const e2eTestDir = join(projectDir, 'e2e');
const outDir = join(outputDir, 'packages', 'e2e-app');

const PROTRACTOR_CONFIG_PATH = join(projectDir, 'test/protractor.conf.js');
const tsconfigPath = join(outDir, 'tsconfig-build.json');
/**
* The output of the e2e app will preserve the directory structure because otherwise NGC is not
* able to generate factory files for the release output and node modules.
*/
const outDir = join(outputDir, 'src/e2e-app');

/** Glob that matches all files that need to be copied to the output folder. */
const assetsGlob = join(appDir, '**/*.+(html|css|json|ts)');
const PROTRACTOR_CONFIG_PATH = join(projectDir, 'test/protractor.conf.js');
const tsconfigPath = join(appDir, 'tsconfig-build.json');

/** Builds and serves the e2e-app and runs protractor once the e2e-app is ready. */
task('e2e', sequenceTask(
Expand Down Expand Up @@ -68,12 +66,11 @@ task('e2e-app:build', sequenceTask(
'material-moment-adapter:build-release',
'material-examples:build-release'
],
['e2e-app:copy-release', 'e2e-app:copy-assets'],
'e2e-app:build-ts'
['e2e-app:copy-index-html', 'e2e-app:build-ts']
));

/** Task that copies all required assets to the output folder. */
task('e2e-app:copy-assets', copyTask(assetsGlob, outDir));
/** Task that copies the e2e-app index HTML file to the output. */
task('e2e-app:copy-index-html', copyTask(join(appDir, 'index.html'), outDir));

/** Task that builds the TypeScript sources. Those are compiled inside of the dist folder. */
task('e2e-app:build-ts', ngcBuildTask(tsconfigPath));
Expand All @@ -84,13 +81,31 @@ task(':watch:e2eapp', () => {
});

/** Ensures that protractor and webdriver are set up to run. */
task(':test:protractor:setup', execNodeTask('protractor', 'webdriver-manager', ['update']));
task(':test:protractor:setup', execNodeTask(
// Disable download of the gecko selenium driver because otherwise the webdriver
// manager queries GitHub for the latest version and will result in rate limit failures.
'protractor', 'webdriver-manager', ['update', '--gecko', 'false']));

/** Runs protractor tests (assumes that server is already running. */
task(':test:protractor', execNodeTask('protractor', [PROTRACTOR_CONFIG_PATH]));

/** Starts up the e2e app server. */
task(':serve:e2eapp', serverTask(outDir, false));
/** Starts up the e2e app server and rewrites the HTTP requests to properly work with AOT. */
task(':serve:e2eapp', serverTask(outDir, false, [
// Rewrite each request for .ngfactory files which are outside of the e2e-app to the **actual**
// path. This is necessary because NGC cannot generate factory files for the node modules
// and release output. If we work around it by adding multiple root directories, the directory
// structure would be messed up, so we need to go this way for now (until Ivy).
{ from: '^/((?:dist|node_modules)/.*\.ngfactory\.js)$', to: '/dist/$1' },
// Rewrite the node_modules/ and dist/ folder to the real paths. Otherwise we would need
// to copy the required modules to the serve output. If dist/ is explicitly requested, we
// should redirect to the actual dist path because by default we fall back to the e2e output.
{ from: '^/node_modules/(.*)$', to: '/node_modules/$1' },
{ from: '^/dist/(.*)$', to: '/dist/$1' },
// Rewrite every path that doesn't point to a specific file to the e2e output.
// This is necessary for Angular's routing using the HTML5 History API.
{ from: '^/[^.]+$', to: `/dist/src/e2e-app/index.html`},
{ from: '^(.*)$', to: `/dist/src/e2e-app/$1` },
]));

/** Terminates the e2e app server */
task(':serve:e2eapp:stop', gulpConnect.serverClose);
Expand All @@ -103,14 +118,3 @@ task('serve:e2eapp', sequenceTask('e2e-app:build', ':serve:e2eapp'));
* This should only be used when running e2e tests locally.
*/
task('serve:e2eapp:watch', ['serve:e2eapp', 'material:watch', ':watch:e2eapp']);

// As a workaround for https://github.com/angular/angular/issues/12249, we need to
// copy the Material and CDK ESM output inside of the demo-app output.
task('e2e-app:copy-release', () => {
copySync(join(releasesDir, 'cdk'), join(outDir, 'cdk'));
copySync(join(releasesDir, 'material'), join(outDir, 'material'));
copySync(join(releasesDir, 'cdk-experimental'), join(outDir, 'cdk-experimental'));
copySync(join(releasesDir, 'material-experimental'), join(outDir, 'material-experimental'));
copySync(join(releasesDir, 'material-examples'), join(outDir, 'material-examples'));
copySync(join(releasesDir, 'material-moment-adapter'), join(outDir, 'material-moment-adapter'));
});
29 changes: 16 additions & 13 deletions tools/gulp/util/task_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,22 @@ export function cleanTask(glob: string) {
* Create a task that serves a given directory in the project.
* The server rewrites all node_module/ or dist/ requests to the correct directory.
*/
export function serverTask(packagePath: string, livereload = true) {
// The http-rewrite-middlware only supports relative paths as rewrite destinations.
export function serverTask(packagePath: string, livereload = true,
rewrites?: {from: string, to: string}[]) {

// The http-rewrite-middleware only supports relative paths as rewrite destinations.
const relativePath = path.relative(projectDir, packagePath);
const defaultHttpRewrites = [
// Rewrite the node_modules/ and dist/ folder to the real paths. This is a trick to
// avoid that those folders will be rewritten to the specified package path.
{ from: '^/node_modules/(.*)$', to: '/node_modules/$1' },
{ from: '^/dist/(.*)$', to: '/dist/$1' },
// Rewrite every path that doesn't point to a specific file to the index.html file.
// This is necessary for Angular's routing using the HTML5 History API.
{ from: '^/[^.]+$', to: `/${relativePath}/index.html`},
// Rewrite any path that didn't match a pattern before to the specified package path.
{ from: '^(.*)$', to: `/${relativePath}/$1` },
];

return () => {
gulpConnect.server({
Expand All @@ -137,17 +150,7 @@ export function serverTask(packagePath: string, livereload = true) {
port: 4200,
host: '0.0.0.0',
middleware: () => {
return [httpRewrite.getMiddleware([
// Rewrite the node_modules/ and dist/ folder to the real paths. This is a trick to
// avoid that those folders will be rewritten to the specified package path.
{ from: '^/node_modules/(.*)$', to: '/node_modules/$1' },
{ from: '^/dist/(.*)$', to: '/dist/$1' },
// Rewrite every path that doesn't point to a specific file to the index.html file.
// This is necessary for Angular's routing using the HTML5 History API.
{ from: '^/[^.]+$', to: `/${relativePath}/index.html`},
// Rewrite any path that didn't match a pattern before to the specified package path.
{ from: '^(.*)$', to: `/${relativePath}/$1` },
])];
return [httpRewrite.getMiddleware(rewrites || defaultHttpRewrites)];
}
});
};
Expand Down