blob: 60fcea3d7a5565debedcc0d1c55ff24e3a8f4dbb [file] [log] [blame]
Frank Borden68876a32022-09-14 11:39:16 +02001/**
2 * @license
3 * Copyright 2020 Google LLC
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7const runUnderBazel = !!process.env["RUNFILES_DIR"];
8const path = require("path");
9
10function getModulesDir() {
11 if (runUnderBazel) {
12 // Run under bazel
13 return [
14 `external/plugins_npm/node_modules`,
15 `external/ui_npm/node_modules`,
16 `external/ui_dev_npm/node_modules`,
17 ];
18 }
19
20 // Run from intellij or npm run test:kdebug
21 return [
22 path.join(__dirname, "app/node_modules"),
23 path.join(__dirname, "node_modules"),
24 ];
25}
26
27function getUiDevNpmFilePath(importPath) {
28 if (runUnderBazel) {
29 return `external/ui_dev_npm/node_modules/${importPath}`;
30 } else {
31 return `polygerrit-ui/node_modules/${importPath}`;
32 }
33}
34
35function runInIde() {
36 // A simple detection of IDE.
37 // Default browserNoActivityTimeout is 30 seconds. An IDE usually
38 // runs karma in background and send commands when a user wants to
39 // execute test. If interval between user executed tests is bigger than
40 // browserNoActivityTimeout, the IDE reports error and doesn't restart
41 // server.
42 // We want to increase browserNoActivityTimeout when tests run in IDE.
43 // Wd don't want to increase it in other cases, oterhise hanging tests
44 // can slow down CI.
45 return (
46 !runUnderBazel &&
47 process.argv.some((arg) => arg.toLowerCase().contains("intellij"))
48 );
49}
50
51module.exports = function (config) {
52 let root = config.root;
53 if (!root) {
54 console.warn(`--root argument not set. Falling back to __dirname.`);
55 root = path.resolve(__dirname) + "/";
56 }
57 // Use --test-files to specify pattern for a test files.
58 // It can be just a file name, without a path:
59 // --test-files async-foreach-behavior_test.js
60 // If you specify --test-files without pattern, it gets true value
61 // In this case we will run all tests (usefull for package.json "debugtest"
62 // script)
63 // We will convert a .ts argument to .js and fill in .js if no extension is
64 // given.
65 let filePattern;
66 if (typeof config.testFiles === "string") {
67 if (config.testFiles.endsWith(".ts")) {
68 filePattern =
69 config.testFiles.substr(0, config.testFiles.lastIndexOf(".")) + ".js";
70 } else if (config.testFiles.endsWith(".js")) {
71 filePattern = config.testFiles;
72 } else {
73 filePattern = config.testFiles + ".js";
74 }
75 } else {
76 filePattern = "*_test.js";
77 }
78 const testFilesPattern = root + "**/" + filePattern;
79
80 console.info(`Karma test file pattern: ${testFilesPattern}`);
81 // Special patch for grep parameters (see details in the grep-patch-karam.js)
82 const additionalFiles = runUnderBazel
83 ? []
84 : ["polygerrit-ui/grep-patch-karma.js"];
85 config.set({
86 browserNoActivityTimeout: runInIde ? 60 * 60 * 1000 : 30 * 1000,
87 // base path that will be used to resolve all patterns (eg. files, exclude)
88 basePath: "../",
89 plugins: [
90 // Do not use karma-* to load all installed plugin
91 // This can lead to unexpected behavior under bazel
92 // if you forget to add a plugin in a bazel rule.
93 require.resolve("@open-wc/karma-esm"),
94 "karma-mocha",
95 "karma-chrome-launcher",
96 "karma-mocha-reporter",
97 ],
98 // frameworks to use
99 // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
100 frameworks: ["mocha", "esm"],
101
102 // list of files / patterns to load in the browser
103 files: [
104 ...additionalFiles,
105 getUiDevNpmFilePath("source-map-support/browser-source-map-support.js"),
106 getUiDevNpmFilePath(
107 "accessibility-developer-tools/dist/js/axs_testing.js"
108 ),
109 {
110 pattern: getUiDevNpmFilePath("@open-wc/semantic-dom-diff/index.js"),
111 type: "module",
112 },
113 {
114 pattern: getUiDevNpmFilePath("@open-wc/testing-helpers/index.js"),
115 type: "module",
116 },
117 getUiDevNpmFilePath("sinon/pkg/sinon.js"),
118 { pattern: testFilesPattern, type: "module" },
119 ],
120 esm: {
121 nodeResolve: {
122 // By default, it tries to use page.mjs file instead of page.js
123 // when importing 'page/page', so we shouldn't use .mjs extension
124 // in node resolve.
125 // The .ts extension is required to display source code in browser
126 // (otherwise esm plugin crashes)
127 extensions: [".js", ".ts"],
128 },
129 moduleDirs: getModulesDir(),
130 // Bazel and yarn uses symlinks for files.
131 // preserveSymlinks is necessary for correct modules paths resolving
132 preserveSymlinks: true,
133 // By default, esm-dev-server uses 'auto' compatibility mode.
134 // In the 'auto' mode it incorrectly applies polyfills and
135 // breaks tests in some browser versions
136 // (for example, Chrome 69 on gerrit-ci).
137 compatibility: "none",
138 plugins: [
139 {
140 resolveImport(importSpecifier) {
141 // esm-dev-server interprets .ts files as .js files and
142 // tries to replace all module imports with relative/absolute
143 // paths. In most cases this works correctly. However if
144 // a ts file imports type from .d.ts and there is no
145 // associated .js file then the esm-dev-server responds with
146 // 500 error.
147 // For example the following import .ts file causes problem
148 // import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
149 // To avoid problems, we don't resolve imports in .ts files
150 // and instead always return original path
151 if (importSpecifier.context.originalUrl.endsWith(".ts")) {
152 return importSpecifier.source;
153 }
154 return undefined;
155 },
156 },
157 {
158 transform(context) {
159 if (context.path.endsWith("/node_modules/page/page.js")) {
160 const orignalBody = context.body;
161 // Can't import page.js directly, because this is undefined.
162 // Replace it with window
163 // The same replace exists in server.go
164 // Rollup makes this replacement automatically
165 const transformedBody = orignalBody.replace(
166 "}(this, (function () { 'use strict';",
167 "}(window, (function () { 'use strict';"
168 );
169 if (orignalBody.length === transformedBody.length) {
170 console.error(
171 "The page.js was updated. Please update transform accordingly"
172 );
173 process.exit(1);
174 }
175 return { body: transformedBody };
176 }
177 },
178 },
179 ],
180 },
181 // test results reporter to use
182 // possible values: 'dots', 'progress'
183 // available reporters: https://npmjs.org/browse/keyword/karma-reporter
184 reporters: ["mocha"],
185
186 mochaReporter: {
187 showDiff: true,
188 },
189
190 // Listen on localhost so it either listens to ipv4
191 // or ipv6. Some OS's default to ipv6 for localhost
192 // and others ipv4.
193 // Nodejs 17 changed the behaviour from prefering ipv4 to
194 // using the OS settings.
195 // The default is 127.0.0.1 thus if localhost is on ipv6 only
196 // it'll fail to connect to the karma server.
197 // See https://github.com/karma-runner/karma/blob/e17698f950af83bf2b3edc540d2a3e1fb73cba59/lib/utils/dns-utils.js#L3
198 listenAddress: "localhost",
199
200 // web server port
201 port: 9876,
202
203 // enable / disable colors in the output (reporters and logs)
204 colors: true,
205
206 // level of logging
207 // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
208 logLevel: config.LOG_INFO,
209
210 // enable / disable watching file and executing tests whenever any file changes
211 autoWatch: false,
212
213 // start these browsers
214 // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
215 browsers: ["CustomChromeHeadless"],
216 browserForDebugging: "CustomChromeHeadlessWithDebugPort",
217
218 // Continuous Integration mode
219 // if true, Karma captures browsers, runs the tests and exits
220 singleRun: true,
221
222 // Concurrency level
223 // how many browser should be started simultaneous
224 concurrency: Infinity,
225
226 client: {
227 mocha: {
228 ui: "tdd",
229 timeout: 5000,
230 },
231 },
232
233 customLaunchers: {
234 // Based on https://developers.google.com/web/updates/2017/06/headless-karma-mocha-chai
235 CustomChromeHeadless: {
236 base: "ChromeHeadless",
237 flags: ["--disable-translate", "--disable-extensions"],
238 },
239 ChromeDev: {
240 base: "Chrome",
241 flags: ["--disable-extensions", " --auto-open-devtools-for-tabs"],
242 },
243 CustomChromeHeadlessWithDebugPort: {
244 base: "CustomChromeHeadless",
245 flags: ["--remote-debugging-port=9222"],
246 },
247 },
248 });
249};