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=');
+}