diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index cd5b1af46..84fb676cb 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -1,5 +1,6 @@ # Forked from: https://github.com/angular/components/blob/8ac3ca11add4ae194b2b79169559fb3dbad7e161/tools/BUILD.bazel load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") +load("@io_bazel_rules_webtesting//web:web.bzl", "browser") package(default_visibility = ["//visibility:public"]) @@ -34,3 +35,30 @@ config_setting( name = "stamp", values = {"stamp": "true"}, ) + +PLATFORM_METADATA = select({ + "@npm//@angular/build-tooling/bazel/constraints:linux_x64": [ + "@org_chromium_chromedriver_linux_x64//:metadata", + "@org_chromium_chromium_linux_x64//:metadata", + ], + "@npm//@angular/build-tooling/bazel/constraints:macos_x64": [ + "@org_chromium_chromedriver_macos_x64//:metadata", + "@org_chromium_chromium_macos_x64//:metadata", + ], + "@npm//@angular/build-tooling/bazel/constraints:macos_arm64": [ + "@org_chromium_chromedriver_macos_arm64//:metadata", + "@org_chromium_chromium_macos_arm64//:metadata", + ], + "@npm//@angular/build-tooling/bazel/constraints:windows_x64": [ + "@org_chromium_chromedriver_windows//:metadata", + "@org_chromium_chromium_windows//:metadata", + ], +}) + +browser( + name = "chromium", + metadata = "chromium.json", + deps = PLATFORM_METADATA + [ + "@io_bazel_rules_webtesting//go/wsl", + ], +) diff --git a/tools/chromium.json b/tools/chromium.json new file mode 100644 index 000000000..8cfd9bc21 --- /dev/null +++ b/tools/chromium.json @@ -0,0 +1,17 @@ +{ + "environment": "local", + "capabilities": { + "browserName": "chrome", + "goog:chromeOptions": { + "binary": "%FILE:CHROMIUM%", + "args": ["--no-sandbox", "--headless", "--use-gl=swiftshader-webgl"] + }, + "google:wslConfig": { + "binary": "%FILE:CHROMEDRIVER%", + "port": "%WSLPORT:WSL%", + "args": ["--port=%WSLPORT:WSL%"], + "status": true, + "shutdown": true + } + } +} diff --git a/tools/defaults.bzl b/tools/defaults.bzl index d67ca846d..c0850793d 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -258,7 +258,7 @@ def karma_web_test_suite(name, **kwargs): kwargs["tags"] = ["native"] + kwargs.get("tags", []) kwargs["browsers"] = [ - "@npm//@angular/build-tooling/bazel/browsers/chromium:chromium", + "//tools:chromium", ] # Filter out options which are specific to "karma_web_test" targets. We cannot diff --git a/tools/test/bazel-karma-local-config.js b/tools/test/bazel-karma-local-config.js index 37469e83c..0ee466257 100644 --- a/tools/test/bazel-karma-local-config.js +++ b/tools/test/bazel-karma-local-config.js @@ -1,49 +1,49 @@ -// Forked from: https://github.com/angular/components/blob/8ac3ca11add4ae194b2b79169559fb3dbad7e161/test/bazel-karma-local-config.js -/** - * Karma configuration that is used by Bazel karma_web_test targets which do not - * want to launch any browser and just enable manual browser debugging. - */ +// // Forked from: https://github.com/angular/components/blob/8ac3ca11add4ae194b2b79169559fb3dbad7e161/test/bazel-karma-local-config.js +// /** +// * Karma configuration that is used by Bazel karma_web_test targets which do not +// * want to launch any browser and just enable manual browser debugging. +// */ -module.exports = (config) => { - const overwrites = {}; +// module.exports = (config) => { +// const overwrites = {}; - // By default "@bazel/concatjs" configures Chrome as browser. Since we don't want - // to launch any browser at all, we overwrite the "browsers" option. Since the - // default config tries to extend the browsers array with "Chrome", we need to - // always return a new empty array. - Object.defineProperty(overwrites, 'browsers', { - get: () => [], - set: () => {}, - enumerable: true, - }); +// // By default "@bazel/concatjs" configures Chrome as browser. Since we don't want +// // to launch any browser at all, we overwrite the "browsers" option. Since the +// // default config tries to extend the browsers array with "Chrome", we need to +// // always return a new empty array. +// Object.defineProperty(overwrites, 'browsers', { +// get: () => [], +// set: () => {}, +// enumerable: true, +// }); - // Ensures that tests start executing once browsers have been manually connected. We need - // to use "defineProperty" because the default "@bazel/concatjs" config overwrites the option. - Object.defineProperty(overwrites, 'autoWatch', { - get: () => true, - set: () => {}, - enumerable: true, - }); +// // Ensures that tests start executing once browsers have been manually connected. We need +// // to use "defineProperty" because the default "@bazel/concatjs" config overwrites the option. +// Object.defineProperty(overwrites, 'autoWatch', { +// get: () => true, +// set: () => {}, +// enumerable: true, +// }); - // When not running with ibazel, do not set up the `@bazel/concatjs` watcher. This one - // relies on ibazel to write to the `stdin` interface. When running without ibazel, the - // watcher will kill concatjs since there is no data written to the `stdin` interface. - if (process.env['IBAZEL_NOTIFY_CHANGES'] !== 'y') { - // We pre-define a plugins array that captures registration of Karma plugins - // and unsets the watcher definitions so that no watcher can be configured. - overwrites.plugins = new KarmaPluginArrayWithoutWatchers(); - } +// // When not running with ibazel, do not set up the `@bazel/concatjs` watcher. This one +// // relies on ibazel to write to the `stdin` interface. When running without ibazel, the +// // watcher will kill concatjs since there is no data written to the `stdin` interface. +// if (process.env['IBAZEL_NOTIFY_CHANGES'] !== 'y') { +// // We pre-define a plugins array that captures registration of Karma plugins +// // and unsets the watcher definitions so that no watcher can be configured. +// overwrites.plugins = new KarmaPluginArrayWithoutWatchers(); +// } - config.set(overwrites); -}; +// config.set(overwrites); +// }; -class KarmaPluginArrayWithoutWatchers extends Array { - // The Bazel Karma rules only register new plugins using `.push`. - push(...plugins) { - plugins - .filter((p) => typeof p === 'object') - .forEach((p) => delete p.watcher); +// class KarmaPluginArrayWithoutWatchers extends Array { +// // The Bazel Karma rules only register new plugins using `.push`. +// push(...plugins) { +// plugins +// .filter((p) => typeof p === 'object') +// .forEach((p) => delete p.watcher); - super.push(...plugins); - } -} +// super.push(...plugins); +// } +// } diff --git a/tools/test/karma.conf.js b/tools/test/karma.conf.js index 9f422bb4c..7e0fb7980 100644 --- a/tools/test/karma.conf.js +++ b/tools/test/karma.conf.js @@ -1,221 +1,221 @@ -// Forked from: https://github.com/angular/components/blob/8ac3ca11add4ae194b2b79169559fb3dbad7e161/test/karma.conf.js - -const path = require('path'); -const {customLaunchers, platformMap} = require('./browser-providers'); - -module.exports = (config) => { - config.set({ - basePath: path.join(__dirname, '..'), - frameworks: ['jasmine'], - middleware: ['fake-url'], - plugins: [ - require('karma-jasmine'), - require('karma-browserstack-launcher'), - require('karma-sauce-launcher'), - require('karma-sourcemap-loader'), - { - 'middleware:fake-url': [ - 'factory', - function () { - // Middleware that avoids triggering 404s during tests that need to reference - // image paths. Assumes that the image path will start with `/$`. - return function (request, response, next) { - if (request.url.indexOf('/$') === 0) { - response.writeHead(200); - return response.end(); - } - - next(); - }; - }, - ], - }, - ], - files: [ - { - pattern: 'node_modules/reflect-metadata/Reflect.js', - included: true, - watched: false, - }, - { - pattern: 'node_modules/zone.js/bundles/zone.umd.min.js', - included: true, - watched: false, - }, - { - pattern: 'node_modules/zone.js/bundles/proxy.umd.min.js', - included: true, - watched: false, - }, - { - pattern: 'node_modules/zone.js/bundles/sync-test.umd.js', - included: true, - watched: false, - }, - { - pattern: 'node_modules/zone.js/bundles/jasmine-patch.umd.min.js', - included: true, - watched: false, - }, - { - pattern: 'node_modules/zone.js/bundles/async-test.umd.js', - included: true, - watched: false, - }, - { - pattern: 'node_modules/zone.js/bundles/fake-async-test.umd.js', - included: true, - watched: false, - }, - { - pattern: 'node_modules/moment/min/moment-with-locales.min.js', - included: false, - watched: false, - }, - { - pattern: 'node_modules/luxon/build/amd/**/*', - included: false, - watched: false, - }, - { - pattern: 'node_modules/@material/*/dist/*', - included: false, - watched: false, - }, - {pattern: 'node_modules/kagekiri/**', included: false, watched: false}, - - // is copied into the "dist/" folder so that the Karma config can use it. - { - pattern: 'dist/legacy-test-bundle.spec.js', - included: true, - watched: false, - }, - - // Include a Material theme in the test suite. Also include the MDC theme as - // karma runs tests for the MDC prototype components as well. - { - pattern: 'src/material/core/theming/prebuilt/indigo-pink.css', - included: true, - watched: true, - }, - ], - - customLaunchers: customLaunchers, - - preprocessors: {'dist/*.js': ['sourcemap']}, - - reporters: ['dots'], - autoWatch: false, - - sauceLabs: { - testName: 'Angular Material Unit Tests', - startConnect: false, - recordVideo: false, - recordScreenshots: false, - idleTimeout: 1000, - commandTimeout: 600, - maxDuration: 5400, - }, - - browserStack: { - project: 'Angular Material Unit Tests', - startTunnel: true, - retryLimit: 3, - timeout: 1800, - video: false, - }, - - browserDisconnectTolerance: 1, - browserNoActivityTimeout: 300000, - - browsers: [], - singleRun: false, - - // Try Websocket for a faster transmission first. Fallback to polling if necessary. - transports: ['websocket', 'polling'], - - browserConsoleLogOptions: {terminal: true, level: 'log'}, - - client: { - jasmine: { - // TODO(jelbourn): re-enable random test order once we can de-flake existing issues. - random: false, - }, - }, - }); - - if (process.env['CI']) { - const containerInstanceIndex = Number(process.env['CI_NODE_INDEX']) || 0; - const maxParallelContainerInstances = - Number(process.env['CI_NODE_TOTAL']) || 1; - const tunnelIdentifier = `angular-material-${process.env['CI_RUNNER_NUMBER']}-${containerInstanceIndex}`; - const buildIdentifier = `ci-${tunnelIdentifier}`; - const testPlatform = process.env['TEST_PLATFORM']; - - // This defines how often a given browser should be launched in the same CI - // container. This is helpful if we want to shard tests across the same browser. - const parallelBrowserInstances = - Number(process.env['KARMA_PARALLEL_BROWSERS']) || 1; - - // In case there should be multiple instances of the browsers, we need to set up the - // the karma-parallel plugin. - if (parallelBrowserInstances > 1) { - config.frameworks.unshift('parallel'); - config.plugins.push(require('karma-parallel')); - config.parallelOptions = { - executors: parallelBrowserInstances, - shardStrategy: 'round-robin', - }; - } - - if (testPlatform === 'browserstack') { - config.browserStack.build = buildIdentifier; - config.browserStack.tunnelIdentifier = tunnelIdentifier; - } else if (testPlatform === 'saucelabs') { - config.sauceLabs.build = buildIdentifier; - config.sauceLabs.tunnelIdentifier = tunnelIdentifier; - // Setup the saucelabs reporter so that we report back to Saucelabs once - // our tests finished. - config.reporters.push('saucelabs'); - } - - // If the test platform is not "local", browsers are launched externally and can take - // up more time to capture. Also the connection can be flaky and therefore needs a - // higher disconnect timeout. - if (testPlatform !== 'local') { - config.browserDisconnectTimeout = 180000; - config.browserDisconnectTolerance = 3; - config.captureTimeout = 180000; - } - - const platformBrowsers = platformMap[testPlatform]; - const browserInstanceChunks = splitBrowsersIntoInstances( - platformBrowsers, - maxParallelContainerInstances, - ); - - // Configure Karma to launch the browsers that belong to the given test platform and - // container instance. - config.browsers = browserInstanceChunks[containerInstanceIndex]; - } -}; - -/** - * Splits the specified browsers into a maximum amount of chunks. The chunk of browsers - * are being created deterministically and therefore we get reproducible tests when executing - * the same CircleCI instance multiple times. - */ -function splitBrowsersIntoInstances(browsers, maxInstances) { - let chunks = []; - let assignedBrowsers = 0; - - for (let i = 0; i < maxInstances; i++) { - const chunkSize = Math.floor( - (browsers.length - assignedBrowsers) / (maxInstances - i), - ); - chunks[i] = browsers.slice(assignedBrowsers, assignedBrowsers + chunkSize); - assignedBrowsers += chunkSize; - } - - return chunks; -} +// // Forked from: https://github.com/angular/components/blob/8ac3ca11add4ae194b2b79169559fb3dbad7e161/test/karma.conf.js + +// const path = require('path'); +// const {customLaunchers, platformMap} = require('./browser-providers'); + +// module.exports = (config) => { +// config.set({ +// basePath: path.join(__dirname, '..'), +// frameworks: ['jasmine'], +// middleware: ['fake-url'], +// plugins: [ +// require('karma-jasmine'), +// require('karma-browserstack-launcher'), +// require('karma-sauce-launcher'), +// require('karma-sourcemap-loader'), +// { +// 'middleware:fake-url': [ +// 'factory', +// function () { +// // Middleware that avoids triggering 404s during tests that need to reference +// // image paths. Assumes that the image path will start with `/$`. +// return function (request, response, next) { +// if (request.url.indexOf('/$') === 0) { +// response.writeHead(200); +// return response.end(); +// } + +// next(); +// }; +// }, +// ], +// }, +// ], +// files: [ +// { +// pattern: 'node_modules/reflect-metadata/Reflect.js', +// included: true, +// watched: false, +// }, +// { +// pattern: 'node_modules/zone.js/bundles/zone.umd.min.js', +// included: true, +// watched: false, +// }, +// { +// pattern: 'node_modules/zone.js/bundles/proxy.umd.min.js', +// included: true, +// watched: false, +// }, +// { +// pattern: 'node_modules/zone.js/bundles/sync-test.umd.js', +// included: true, +// watched: false, +// }, +// { +// pattern: 'node_modules/zone.js/bundles/jasmine-patch.umd.min.js', +// included: true, +// watched: false, +// }, +// { +// pattern: 'node_modules/zone.js/bundles/async-test.umd.js', +// included: true, +// watched: false, +// }, +// { +// pattern: 'node_modules/zone.js/bundles/fake-async-test.umd.js', +// included: true, +// watched: false, +// }, +// { +// pattern: 'node_modules/moment/min/moment-with-locales.min.js', +// included: false, +// watched: false, +// }, +// { +// pattern: 'node_modules/luxon/build/amd/**/*', +// included: false, +// watched: false, +// }, +// { +// pattern: 'node_modules/@material/*/dist/*', +// included: false, +// watched: false, +// }, +// {pattern: 'node_modules/kagekiri/**', included: false, watched: false}, + +// // is copied into the "dist/" folder so that the Karma config can use it. +// { +// pattern: 'dist/legacy-test-bundle.spec.js', +// included: true, +// watched: false, +// }, + +// // Include a Material theme in the test suite. Also include the MDC theme as +// // karma runs tests for the MDC prototype components as well. +// { +// pattern: 'src/material/core/theming/prebuilt/indigo-pink.css', +// included: true, +// watched: true, +// }, +// ], + +// customLaunchers: customLaunchers, + +// preprocessors: {'dist/*.js': ['sourcemap']}, + +// reporters: ['dots'], +// autoWatch: false, + +// sauceLabs: { +// testName: 'Angular Material Unit Tests', +// startConnect: false, +// recordVideo: false, +// recordScreenshots: false, +// idleTimeout: 1000, +// commandTimeout: 600, +// maxDuration: 5400, +// }, + +// browserStack: { +// project: 'Angular Material Unit Tests', +// startTunnel: true, +// retryLimit: 3, +// timeout: 1800, +// video: false, +// }, + +// browserDisconnectTolerance: 1, +// browserNoActivityTimeout: 300000, + +// browsers: [], +// singleRun: false, + +// // Try Websocket for a faster transmission first. Fallback to polling if necessary. +// transports: ['websocket', 'polling'], + +// browserConsoleLogOptions: {terminal: true, level: 'log'}, + +// client: { +// jasmine: { +// // TODO(jelbourn): re-enable random test order once we can de-flake existing issues. +// random: false, +// }, +// }, +// }); + +// if (process.env['CI']) { +// const containerInstanceIndex = Number(process.env['CI_NODE_INDEX']) || 0; +// const maxParallelContainerInstances = +// Number(process.env['CI_NODE_TOTAL']) || 1; +// const tunnelIdentifier = `angular-material-${process.env['CI_RUNNER_NUMBER']}-${containerInstanceIndex}`; +// const buildIdentifier = `ci-${tunnelIdentifier}`; +// const testPlatform = process.env['TEST_PLATFORM']; + +// // This defines how often a given browser should be launched in the same CI +// // container. This is helpful if we want to shard tests across the same browser. +// const parallelBrowserInstances = +// Number(process.env['KARMA_PARALLEL_BROWSERS']) || 1; + +// // In case there should be multiple instances of the browsers, we need to set up the +// // the karma-parallel plugin. +// if (parallelBrowserInstances > 1) { +// config.frameworks.unshift('parallel'); +// config.plugins.push(require('karma-parallel')); +// config.parallelOptions = { +// executors: parallelBrowserInstances, +// shardStrategy: 'round-robin', +// }; +// } + +// if (testPlatform === 'browserstack') { +// config.browserStack.build = buildIdentifier; +// config.browserStack.tunnelIdentifier = tunnelIdentifier; +// } else if (testPlatform === 'saucelabs') { +// config.sauceLabs.build = buildIdentifier; +// config.sauceLabs.tunnelIdentifier = tunnelIdentifier; +// // Setup the saucelabs reporter so that we report back to Saucelabs once +// // our tests finished. +// config.reporters.push('saucelabs'); +// } + +// // If the test platform is not "local", browsers are launched externally and can take +// // up more time to capture. Also the connection can be flaky and therefore needs a +// // higher disconnect timeout. +// if (testPlatform !== 'local') { +// config.browserDisconnectTimeout = 180000; +// config.browserDisconnectTolerance = 3; +// config.captureTimeout = 180000; +// } + +// const platformBrowsers = platformMap[testPlatform]; +// const browserInstanceChunks = splitBrowsersIntoInstances( +// platformBrowsers, +// maxParallelContainerInstances, +// ); + +// // Configure Karma to launch the browsers that belong to the given test platform and +// // container instance. +// config.browsers = browserInstanceChunks[containerInstanceIndex]; +// } +// }; + +// /** +// * Splits the specified browsers into a maximum amount of chunks. The chunk of browsers +// * are being created deterministically and therefore we get reproducible tests when executing +// * the same CircleCI instance multiple times. +// */ +// function splitBrowsersIntoInstances(browsers, maxInstances) { +// let chunks = []; +// let assignedBrowsers = 0; + +// for (let i = 0; i < maxInstances; i++) { +// const chunkSize = Math.floor( +// (browsers.length - assignedBrowsers) / (maxInstances - i), +// ); +// chunks[i] = browsers.slice(assignedBrowsers, assignedBrowsers + chunkSize); +// assignedBrowsers += chunkSize; +// } + +// return chunks; +// }