diff --git a/tests/legacy-cli/e2e.bzl b/tests/legacy-cli/e2e.bzl index e30c4417fa01..040c143cc2f6 100644 --- a/tests/legacy-cli/e2e.bzl +++ b/tests/legacy-cli/e2e.bzl @@ -50,6 +50,7 @@ WEBPACK_IGNORE_TESTS = [ "tests/build/prerender/error-with-sourcemaps.js", "tests/build/server-rendering/server-routes-*", "tests/build/wasm-esm.js", + "tests/build/auto-csp*", ] def _to_glob(patterns): diff --git a/tests/legacy-cli/e2e/tests/build/auto-csp.ts b/tests/legacy-cli/e2e/tests/build/auto-csp.ts new file mode 100644 index 000000000000..1ea1aa5641d5 --- /dev/null +++ b/tests/legacy-cli/e2e/tests/build/auto-csp.ts @@ -0,0 +1,136 @@ +import assert from 'node:assert'; +import { getGlobalVariable } from '../../utils/env'; +import { expectFileToMatch, writeMultipleFiles } from '../../utils/fs'; +import { findFreePort } from '../../utils/network'; +import { execAndWaitForOutputToMatch, ng } from '../../utils/process'; +import { updateJsonFile } from '../../utils/project'; + +const CSP_META_TAG = / { + const build = json['projects']['test-project']['architect']['build']; + build.options = { + ...build.options, + security: { autoCsp: true }, + }; + }); + + await writeMultipleFiles({ + 'serve.js': ` + const express = require('express'); + const path = require('path'); + + const app = express(); + const PORT = process.env.PORT || 3000; + + app.use(express.static(path.join(__dirname, 'dist/test-project/browser'))); + + app.listen(PORT, () => { + console.log('Node Express server listening on ' + PORT); + }); + `, + 'public/script1.js': ` + const externalScriptCreated = 1337; + console.warn('First External Script: ' + inlineScriptBodyCreated); + `, + 'public/script2.js': `console.warn('Second External Script: ' + externalScriptCreated);`, + 'src/index.html': ` + + + + + + + + + + + + + + + + `, + 'e2e/src/app.e2e-spec.ts': ` + import { browser, by, element } from 'protractor'; + import * as webdriver from 'selenium-webdriver'; + + function allConsoleWarnMessagesAndErrors() { + return browser + .manage() + .logs() + .get('browser') + .then(function (browserLog: any[]) { + const warnMessages: any[] = []; + browserLog.filter((logEntry) => { + const msg = logEntry.message; + console.log('>> ' + msg); + if (logEntry.level.value >= webdriver.logging.Level.INFO.value) { + warnMessages.push(msg); + } + }); + return warnMessages; + }); + } + + describe('Hello world E2E Tests', () => { + beforeAll(async () => { + await browser.waitForAngularEnabled(true); + }); + + it('should display: Welcome and run all scripts in order', async () => { + // Load the page without waiting for Angular since it is not bootstrapped automatically. + await browser.driver.get(browser.baseUrl); + + // Test the contents. + expect(await element(by.css('h1')).getText()).toMatch('Hello'); + + // Make sure all scripts ran and there were no client side errors. + const consoleMessages = await allConsoleWarnMessagesAndErrors(); + expect(consoleMessages.length).toEqual(4); // No additional errors + // Extract just the printed messages from the console data. + const printedMessages = consoleMessages.map(m => m.match(/"(.*?)"/)[1]); + expect(printedMessages).toEqual([ + // All messages printed in order because execution order is preserved. + "Inline Script Head", + "Inline Script Body: 1339", + "First External Script: 1338", + "Second External Script: 1337", + ]); + }); + }); + `, + }); + + async function spawnServer(): Promise { + const port = await findFreePort(); + + await execAndWaitForOutputToMatch('node', ['serve.js'], /Node Express server listening on/, { + 'PORT': String(port), + }); + + return port; + } + + await ng('build'); + + // Make sure the output files have auto-CSP as a result of `ng build` + await expectFileToMatch('dist/test-project/browser/index.html', CSP_META_TAG); + + // Make sure that our e2e protractor tests run to confirm that our angular project runs. + const port = await spawnServer(); + await ng('e2e', `--base-url=http://localhost:${port}`, '--dev-server-target='); +}