-
Notifications
You must be signed in to change notification settings - Fork 3.4k
[testing] Improve running browser tests locally. #25013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
brendandahl
merged 12 commits into
emscripten-core:main
from
brendandahl:browser-test-defaults
Aug 26, 2025
Merged
Changes from 8 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
c477e94
[testing] Improve running browser tests locally.
brendandahl 83de3cc
Use string.
brendandahl 0cf3f0b
comment and try to fix firefox
brendandahl 169afad
- use current is_chrome/is_firefox
brendandahl e9a8116
-put browser profile in out dir
brendandahl 1c554bc
default to headed mode
brendandahl 8258ccb
fix env var
brendandahl da4239b
Update test/common.py
brendandahl ec8109a
comments
brendandahl 8aaa1c1
fix firefox
brendandahl bed291f
review
brendandahl 586f88a
no auto delete
brendandahl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,15 +45,21 @@ | |
|
||
# User can specify an environment variable EMTEST_BROWSER to force the browser | ||
# test suite to run using another browser command line than the default system | ||
# browser. | ||
# There are two special value that can be used here if running in an actual | ||
# browser. If only the path to the browser executable is given, the tests | ||
# will run in headless mode with a temporary profile with the same options | ||
# used in CI. To use a custom start command specify the executable and command | ||
# line flags. | ||
# | ||
# There are two special values that can be used here if running in an actual | ||
# browser is not desired: | ||
# EMTEST_BROWSER=0 : This will disable the actual running of the test and simply | ||
# verify that it compiles and links. | ||
# EMTEST_BROWSER=node : This will attempt to run the browser test under node. | ||
# For most browser tests this does not work, but it can | ||
# be useful for running pthread tests under node. | ||
EMTEST_BROWSER = None | ||
EMTEST_BROWSER_AUTO_CONFIG = None | ||
EMTEST_HEADLESS = None | ||
EMTEST_DETECT_TEMPFILE_LEAKS = None | ||
EMTEST_SAVE_DIR = None | ||
# generally js engines are equivalent, testing 1 is enough. set this | ||
|
@@ -76,6 +82,53 @@ | |
if 'EM_BUILD_VERBOSE' in os.environ: | ||
exit_with_error('EM_BUILD_VERBOSE has been renamed to EMTEST_BUILD_VERBOSE') | ||
|
||
|
||
# Default flags used to run browsers in CI testing: | ||
class BrowserConfig: | ||
def __init__(self, data_dir_flag, default_flags, headless_flags): | ||
self.data_dir_flag = data_dir_flag | ||
brendandahl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
self.default_flags = default_flags | ||
self.headless_flags = headless_flags | ||
|
||
def configure(self, data_dir): | ||
pass | ||
|
||
|
||
class ChromeConfig(BrowserConfig): | ||
def __init__(self): | ||
super().__init__( | ||
data_dir_flag = '--user-data-dir=', | ||
default_flags = ( | ||
# --no-sandbox because we are running as root and chrome requires | ||
# this flag for now: https://crbug.com/638180 | ||
'--no-first-run -start-maximized --no-sandbox --enable-unsafe-swiftshader --use-gl=swiftshader --enable-experimental-web-platform-features --enable-features=JavaScriptSourcePhaseImports', | ||
'--enable-experimental-webassembly-features --js-flags="--experimental-wasm-stack-switching --experimental-wasm-type-reflection --experimental-wasm-rab-integration"', | ||
# The runners lack sound hardware so fallback to a dummy device (and | ||
# bypass the user gesture so audio tests work without interaction) | ||
'--use-fake-device-for-media-stream --autoplay-policy=no-user-gesture-required', | ||
# Cache options. | ||
'--disk-cache-size=1 --media-cache-size=1 --disable-application-cache', | ||
), | ||
headless_flags = | ||
# Increase the window size to avoid flaky sdl tests see #24236. | ||
'--headless=new --window-size=1024,768 --remote-debugging-port=1234', | ||
) | ||
|
||
|
||
class FirefoxConfig(BrowserConfig): | ||
def __init__(self): | ||
super().__init__( | ||
data_dir_flag = '-profile ', | ||
default_flags = {}, | ||
headless_flags = '-headless', | ||
) | ||
brendandahl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
def configure(self, data_dir): | ||
shutil.copy(test_file('firefox_user.js'), os.path.join(data_dir, 'user.js')) | ||
|
||
|
||
DEFAULT_BROWSER_DATA_DIR = path_from_root('out/browser-profile') | ||
brendandahl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
# Special value for passing to assert_returncode which means we expect that program | ||
# to fail with non-zero return code, but we don't care about specifically which one. | ||
NON_ZERO = -1 | ||
|
@@ -114,6 +167,17 @@ def has_browser(): | |
return EMTEST_BROWSER != '0' | ||
|
||
|
||
CHROMIUM_BASED_BROWSERS = ['chrom', 'edge', 'opera'] | ||
|
||
|
||
def is_chrome(): | ||
return EMTEST_BROWSER and any(pattern in EMTEST_BROWSER.lower() for pattern in CHROMIUM_BASED_BROWSERS) | ||
|
||
|
||
def is_firefox(): | ||
return EMTEST_BROWSER and 'firefox' in EMTEST_BROWSER.lower() | ||
|
||
|
||
def compiler_for(filename, force_c=False): | ||
if shared.suffix(filename) in ('.cc', '.cxx', '.cpp') and not force_c: | ||
return EMXX | ||
|
@@ -2323,9 +2387,7 @@ def __init__(self, *args, **kwargs): | |
super().__init__(*args, **kwargs) | ||
|
||
@classmethod | ||
def browser_restart(cls): | ||
# Kill existing browser | ||
logger.info('Restarting browser process') | ||
def browser_terminate(cls): | ||
cls.browser_proc.terminate() | ||
# If the browser doesn't shut down gracefully (in response to SIGTERM) | ||
# after 2 seconds kill it with force (SIGKILL). | ||
|
@@ -2335,6 +2397,15 @@ def browser_restart(cls): | |
logger.info('Browser did not respond to `terminate`. Using `kill`') | ||
cls.browser_proc.kill() | ||
cls.browser_proc.wait() | ||
if cls.browser_data_dir: | ||
utils.delete_dir(cls.browser_data_dir) | ||
cls.browser_data_dir = None | ||
brendandahl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
@classmethod | ||
def browser_restart(cls): | ||
# Kill existing browser | ||
logger.info('Restarting browser process') | ||
cls.browser_terminate() | ||
cls.browser_open(cls.HARNESS_URL) | ||
|
||
@classmethod | ||
|
@@ -2343,6 +2414,25 @@ def browser_open(cls, url): | |
if not EMTEST_BROWSER: | ||
logger.info('No EMTEST_BROWSER set. Defaulting to `google-chrome`') | ||
EMTEST_BROWSER = 'google-chrome' | ||
|
||
if EMTEST_BROWSER_AUTO_CONFIG: | ||
logger.info('Using default CI configuration.') | ||
cls.browser_data_dir = DEFAULT_BROWSER_DATA_DIR | ||
if os.path.exists(cls.browser_data_dir): | ||
utils.delete_dir(cls.browser_data_dir) | ||
os.mkdir(cls.browser_data_dir) | ||
if is_chrome(): | ||
config = ChromeConfig() | ||
elif is_firefox(): | ||
config = FirefoxConfig() | ||
else: | ||
logger.warning("Unknown browser type, not using default flags.") | ||
config = BrowserConfig() | ||
EMTEST_BROWSER += f" {config.data_dir_flag}{cls.browser_data_dir} {' '.join(config.default_flags)}" | ||
if EMTEST_HEADLESS == 1: | ||
EMTEST_BROWSER += f" {config.headless_flags}" | ||
config.configure(cls.browser_data_dir) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe "else error" here, "EMTEST_BROWSER_AUTO_CONFIG only currently works with firefox or chrome" |
||
|
||
if WINDOWS: | ||
# On Windows env. vars canonically use backslashes as directory delimiters, e.g. | ||
# set EMTEST_BROWSER=C:\Program Files\Mozilla Firefox\firefox.exe | ||
|
@@ -2373,6 +2463,7 @@ def tearDownClass(cls): | |
return | ||
cls.harness_server.terminate() | ||
print('[Browser harness server terminated]') | ||
cls.browser_terminate() | ||
if WINDOWS: | ||
# On Windows, shutil.rmtree() in tearDown() raises this exception if we do not wait a bit: | ||
# WindowsError: [Error 32] The process cannot access the file because it is being used by another process. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
user_pref("gfx.offscreencanvas.enabled", true); | ||
user_pref("javascript.options.shared_memory", true); | ||
user_pref("javascript.options.wasm_memory64", true); | ||
user_pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", true); | ||
user_pref("media.autoplay.default", 0); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.