| #!/usr/bin/env python3 |
| # Copyright 2019 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Run unittests in a new browser.""" |
| |
| import argparse |
| import logging |
| import os |
| import subprocess |
| import sys |
| |
| import libdot |
| |
| |
| # Path to our html test page. |
| TEST_PAGE = os.path.join(libdot.DIR, 'html', 'lib_test.html') |
| |
| |
| def get_parser(): |
| """Get a parser for our test runner.""" |
| parser = libdot.ArgumentParser( |
| description='HTML test runner', |
| formatter_class=argparse.RawDescriptionHelpFormatter) |
| parser.add_argument('--browser', default=os.getenv('CHROME_BIN'), |
| help='Browser program to run tests against.') |
| parser.add_argument('--profile', default=os.getenv('CHROME_TEST_PROFILE'), |
| help='Browser profile dir to run against.') |
| parser.add_argument('--skip-mkdeps', dest='run_mkdeps', |
| action='store_false', default=True, |
| help='Skip (re)building of dependencies.') |
| parser.add_argument('--visible', action='store_true', |
| help='Show the browser window to interact with.') |
| parser.add_argument('--reporter', default='spec', |
| help='Set the mocha test results report format.') |
| # Note: This CLI option matches Chrome's own naming. |
| parser.add_argument('--no-sandbox', dest='sandbox', |
| action='store_false', default=True, |
| help='Disable Chrome sandboxing.') |
| return parser |
| |
| |
| def test_runner_main(argv, path, serve=False, mkdeps=False): |
| """Open the test page at |path|. |
| |
| Args: |
| argv: The program's command line arguments. |
| path: Path to the test page. |
| serve: Whether to launch a webserver or load the page from disk. |
| mkdeps: Callback to build dependencies after we've initialized. |
| """ |
| parser = get_parser() |
| opts = parser.parse_args(argv) |
| |
| # Try to use default X session. |
| os.environ.setdefault('DISPLAY', ':0') |
| |
| # Ensure chai/mocha node modules exist. |
| libdot.node_and_npm_setup() |
| |
| # Set up any deps. |
| if mkdeps: |
| if opts.run_mkdeps: |
| mkdeps(opts) |
| else: |
| logging.info('Skipping building dependencies due to --skip-mkdeps') |
| |
| # Set up a unique profile to avoid colliding with user settings. |
| profile_dir = opts.profile |
| if not profile_dir: |
| profile_dir = os.path.expanduser('~/.config/google-chrome-run_local') |
| os.makedirs(profile_dir, exist_ok=True) |
| |
| # Find a Chrome version to run against. |
| browser = opts.browser |
| if not browser: |
| browser = libdot.headless_chrome.chrome_setup() |
| |
| # Kick off server if needed. |
| if serve: |
| server = subprocess.Popen( |
| [libdot.node.NODE, |
| os.path.join(libdot.node.NODE_BIN_DIR, 'http-server'), |
| '-a', 'localhost', '-c-1', '--cors'], |
| cwd=libdot.LIBAPPS_DIR) |
| path = 'http://localhost:8080/%s' % path |
| |
| # Some environments are unable to utilize the sandbox: we're not running as |
| # root, and userns is unavailable. For example, while using docker. |
| if opts.sandbox: |
| sb_arg = mocha_sb_arg = [] |
| else: |
| sb_arg = ['--no-sandbox'] |
| # The wrapper requires omitting the leading dashes for no real reason. |
| mocha_sb_arg = ['--args=no-sandbox'] |
| |
| try: |
| # Kick off test runner in the background so we exit. |
| logging.info('Running tests against browser "%s".', browser) |
| logging.info('Tests page: %s', path) |
| if opts.visible: |
| subprocess.Popen([browser, '--user-data-dir=%s' % (profile_dir,), |
| path] + sb_arg) |
| else: |
| # The standalone mocha runner doesn't have a timeout. The headless |
| # one defaults to 1 minute which is too slow for some of our suites. |
| # Increase it to 5 minutes as that should be good enough for all. |
| libdot.node.run(['mocha-headless-chrome', '-e', browser, '-f', path, |
| '--reporter', opts.reporter, '--timeout=300000'] + |
| mocha_sb_arg) |
| finally: |
| # Wait for the server if it exists. |
| if serve: |
| if opts.visible: |
| try: |
| server.wait() |
| except KeyboardInterrupt: |
| pass |
| else: |
| server.terminate() |
| |
| |
| def main(argv): |
| """The main func!""" |
| return test_runner_main(argv, 'file://%s' % (TEST_PAGE,)) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv[1:])) |