| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Copyright 2017 Google Inc. All rights reserved. | 
					
						
							| 
									
										
										
										
											2019-12-10 13:21:51 -08:00
										 |  |  |  * Modifications copyright (c) Microsoft Corporation. | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-04-01 18:02:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  | const fs = require('fs'); | 
					
						
							| 
									
										
										
										
											2020-05-18 19:00:38 -07:00
										 |  |  | const utils = require('./utils'); | 
					
						
							| 
									
										
										
										
											2020-07-08 00:20:36 -07:00
										 |  |  | const path = require('path'); | 
					
						
							|  |  |  | const pirates = require('pirates'); | 
					
						
							|  |  |  | const babel = require('@babel/core'); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  | const TestRunner = require('../utils/testrunner/'); | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  | const { PlaywrightEnvironment, BrowserTypeEnvironment, BrowserEnvironment, PageEnvironment} = require('./environments.js'); | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:55:11 -07:00
										 |  |  | Error.stackTraceLimit = 15; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 10:09:45 -07:00
										 |  |  | function getCLIArgument(argName) { | 
					
						
							|  |  |  |   for (let i = 0; i < process.argv.length; ++i) { | 
					
						
							|  |  |  |     // Support `./test.js --foo bar
 | 
					
						
							|  |  |  |     if (process.argv[i] === argName) | 
					
						
							|  |  |  |       return process.argv[i + 1]; | 
					
						
							|  |  |  |     // Support `./test.js --foo=bar
 | 
					
						
							|  |  |  |     if (argName.startsWith('--') && process.argv[i].startsWith(argName + '=')) | 
					
						
							|  |  |  |       return process.argv[i].substring((argName + '=').length); | 
					
						
							|  |  |  |     // Support `./test.js -j4
 | 
					
						
							|  |  |  |     if (!argName.startsWith('--') && argName.startsWith('-') && process.argv[i].startsWith(argName)) | 
					
						
							|  |  |  |       return process.argv[i].substring(argName.length); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  | function collect(browserNames) { | 
					
						
							|  |  |  |   let parallel = 1; | 
					
						
							|  |  |  |   if (process.env.PW_PARALLEL_TESTS) | 
					
						
							|  |  |  |     parallel = parseInt(process.env.PW_PARALLEL_TESTS.trim(), 10); | 
					
						
							| 
									
										
										
										
											2020-05-01 10:09:45 -07:00
										 |  |  |   if (getCLIArgument('-j')) | 
					
						
							|  |  |  |     parallel = parseInt(getCLIArgument('-j'), 10); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   require('events').defaultMaxListeners *= parallel; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let timeout = process.env.CI ? 30 * 1000 : 10 * 1000; | 
					
						
							|  |  |  |   if (!isNaN(process.env.TIMEOUT)) | 
					
						
							|  |  |  |     timeout = parseInt(process.env.TIMEOUT * 1000, 10); | 
					
						
							|  |  |  |   const MAJOR_NODEJS_VERSION = parseInt(process.version.substring(1).split('.')[0], 10); | 
					
						
							|  |  |  |   if (MAJOR_NODEJS_VERSION >= 8 && require('inspector').url()) { | 
					
						
							|  |  |  |     console.log('Detected inspector - disabling timeout to be debugger-friendly'); | 
					
						
							|  |  |  |     timeout = 0; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-28 08:49:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   const config = require('./test.config'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const testRunner = new TestRunner({ | 
					
						
							|  |  |  |     timeout, | 
					
						
							| 
									
										
										
										
											2020-06-05 17:56:25 -07:00
										 |  |  |     totalTimeout: process.env.CI ? 30 * 60 * 1000 * browserNames.length : 0, // 30 minutes per browser on CI
 | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |     parallel, | 
					
						
							|  |  |  |     breakOnFailure: process.argv.indexOf('--break-on-failure') !== -1, | 
					
						
							|  |  |  |     verbose: process.argv.includes('--verbose'), | 
					
						
							|  |  |  |     summary: !process.argv.includes('--verbose'), | 
					
						
							|  |  |  |     showSlowTests: process.env.CI ? 5 : 0, | 
					
						
							|  |  |  |     showMarkedAsFailingTests: 10, | 
					
						
							| 
									
										
										
										
											2020-05-04 15:15:51 -07:00
										 |  |  |     lineBreak: parseInt(getCLIArgument('--line-break') || 0, 10), | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   if (config.setupTestRunner) | 
					
						
							|  |  |  |     config.setupTestRunner(testRunner); | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   for (const [key, value] of Object.entries(testRunner.api())) | 
					
						
							|  |  |  |     global[key] = value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // TODO: this should be a preinstalled playwright by default.
 | 
					
						
							|  |  |  |   const playwrightPath = config.playwrightPath; | 
					
						
							| 
									
										
										
										
											2020-05-23 00:03:57 -07:00
										 |  |  |   const playwright = require('..'); | 
					
						
							| 
									
										
										
										
											2020-05-08 10:37:54 -07:00
										 |  |  |   const { setUnderTest } = require(require('path').join(playwrightPath, 'lib/helper.js')); | 
					
						
							|  |  |  |   setUnderTest(); | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 18:42:04 -07:00
										 |  |  |   const playwrightEnvironment = new PlaywrightEnvironment(playwright); | 
					
						
							|  |  |  |   testRunner.collector().useEnvironment(playwrightEnvironment); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   for (const e of config.globalEnvironments || []) | 
					
						
							|  |  |  |     testRunner.collector().useEnvironment(e); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 15:00:20 -07:00
										 |  |  |   // TODO(rpc): do not use global playwright and browserType, rely solely on environments.
 | 
					
						
							| 
									
										
										
										
											2020-05-14 13:22:33 -07:00
										 |  |  |   global.playwright = playwright; | 
					
						
							| 
									
										
										
										
											2020-06-25 16:05:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   for (const browserName of browserNames) { | 
					
						
							|  |  |  |     const browserType = playwright[browserName]; | 
					
						
							| 
									
										
										
										
											2020-07-08 18:42:04 -07:00
										 |  |  |     const browserTypeEnvironment = new BrowserTypeEnvironment(browserName); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // TODO: maybe launch options per browser?
 | 
					
						
							|  |  |  |     const launchOptions = { | 
					
						
							|  |  |  |       ...(config.launchOptions || {}), | 
					
						
							|  |  |  |       handleSIGINT: false, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     if (launchOptions.executablePath) | 
					
						
							|  |  |  |       launchOptions.executablePath = launchOptions.executablePath[browserName]; | 
					
						
							|  |  |  |     if (launchOptions.executablePath) { | 
					
						
							|  |  |  |       const YELLOW_COLOR = '\x1b[33m'; | 
					
						
							|  |  |  |       const RESET_COLOR = '\x1b[0m'; | 
					
						
							|  |  |  |       console.warn(`${YELLOW_COLOR}WARN: running ${browserName} tests with ${launchOptions.executablePath}${RESET_COLOR}`); | 
					
						
							|  |  |  |       browserType._executablePath = launchOptions.executablePath; | 
					
						
							|  |  |  |       delete launchOptions.executablePath; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       if (!fs.existsSync(browserType.executablePath())) | 
					
						
							|  |  |  |         throw new Error(`Browser is not downloaded. Run 'npm install' and try to re-run tests`); | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |     const browserEnvironment = new BrowserEnvironment(launchOptions, config.dumpLogOnFailure); | 
					
						
							|  |  |  |     const pageEnvironment = new PageEnvironment(); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const suiteName = { 'chromium': 'Chromium', 'firefox': 'Firefox', 'webkit': 'WebKit' }[browserName]; | 
					
						
							|  |  |  |     describe(suiteName, () => { | 
					
						
							|  |  |  |       // In addition to state, expose these two on global so that describes can access them.
 | 
					
						
							|  |  |  |       global.browserType = browserType; | 
					
						
							| 
									
										
										
										
											2020-05-04 15:15:51 -07:00
										 |  |  |       global.HEADLESS = !!launchOptions.headless; | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       testRunner.collector().useEnvironment(browserTypeEnvironment); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       for (const spec of config.specs || []) { | 
					
						
							|  |  |  |         const skip = spec.browsers && !spec.browsers.includes(browserName); | 
					
						
							|  |  |  |         (skip ? xdescribe : describe)(spec.title || '', () => { | 
					
						
							|  |  |  |           for (const e of spec.environments || ['page']) { | 
					
						
							| 
									
										
										
										
											2020-07-17 08:22:39 -07:00
										 |  |  |             if (e === 'page') { | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |               testRunner.collector().useEnvironment(browserEnvironment); | 
					
						
							|  |  |  |               testRunner.collector().useEnvironment(pageEnvironment); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |               testRunner.collector().useEnvironment(e); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           for (const file of spec.files || []) { | 
					
						
							| 
									
										
										
										
											2020-07-08 00:20:36 -07:00
										 |  |  |             const revert = pirates.addHook((code, filename) => { | 
					
						
							|  |  |  |               const result = babel.transformFileSync(filename, { | 
					
						
							|  |  |  |                 presets: [ | 
					
						
							|  |  |  |                   ['@babel/preset-env', {targets: {node: 'current'}}], | 
					
						
							|  |  |  |                   '@babel/preset-typescript'] | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |               return result.code; | 
					
						
							|  |  |  |             }, { | 
					
						
							|  |  |  |               exts: ['.ts'] | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |             require(file); | 
					
						
							| 
									
										
										
										
											2020-07-08 00:20:36 -07:00
										 |  |  |             revert(); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |             delete require.cache[require.resolve(file)]; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 15:15:51 -07:00
										 |  |  |       delete global.HEADLESS; | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |       delete global.browserType; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (const [key, value] of Object.entries(testRunner.api())) { | 
					
						
							|  |  |  |     // expect is used when running tests, while the rest of api is not.
 | 
					
						
							|  |  |  |     if (key !== 'expect') | 
					
						
							|  |  |  |       delete global[key]; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-21 16:47:38 -07:00
										 |  |  |   return testRunner; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = collect; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if (require.main === module) { | 
					
						
							|  |  |  |   console.log('Testing on Node', process.version); | 
					
						
							|  |  |  |   const browserNames = ['chromium', 'firefox', 'webkit'].filter(name => { | 
					
						
							| 
									
										
										
										
											2020-07-10 13:15:57 -07:00
										 |  |  |     return process.env.BROWSER === name || !process.env.BROWSER; | 
					
						
							| 
									
										
										
										
											2020-04-21 16:47:38 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   const testRunner = collect(browserNames); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 10:09:45 -07:00
										 |  |  |   const testNameFilter = getCLIArgument('--filter'); | 
					
						
							|  |  |  |   if (testNameFilter && !testRunner.focusMatchingNameTests(new RegExp(testNameFilter, 'i')).length) { | 
					
						
							|  |  |  |     console.log('ERROR: no tests matched given `--filter` regex.'); | 
					
						
							|  |  |  |     process.exit(1); | 
					
						
							| 
									
										
										
										
											2020-04-21 16:47:38 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 10:09:45 -07:00
										 |  |  |   const fileNameFilter = getCLIArgument('--file'); | 
					
						
							|  |  |  |   if (fileNameFilter && !testRunner.focusMatchingFileName(new RegExp(fileNameFilter, 'i')).length) { | 
					
						
							|  |  |  |     console.log('ERROR: no files matched given `--file` regex.'); | 
					
						
							|  |  |  |     process.exit(1); | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-04-09 18:14:29 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 10:09:45 -07:00
										 |  |  |   const repeat = parseInt(getCLIArgument('--repeat'), 10); | 
					
						
							|  |  |  |   if (!isNaN(repeat)) | 
					
						
							|  |  |  |     testRunner.repeatAll(repeat); | 
					
						
							| 
									
										
										
										
											2020-04-16 18:09:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-10 20:31:50 -07:00
										 |  |  |   testRunner.run().then(() => { delete global.expect; }); | 
					
						
							|  |  |  | } |