Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions test/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from common import HttpServerThread, requires_dev_dependency
from tools import shared
from tools import ports
from tools.feature_matrix import UNSUPPORTED
from tools.feature_matrix import UNSUPPORTED, min_browser_versions, Feature
from tools.shared import EMCC, WINDOWS, FILE_PACKAGER, PIPE, DEBUG
from tools.utils import delete_dir, memoize

Expand Down Expand Up @@ -158,6 +158,23 @@ def get_safari_version():
return parts[0] * 10000 + parts[1] * 100 + parts[2]


@memoize
def get_firefox_version():
if not is_firefox():
return UNSUPPORTED
exe_path = shlex.split(common.EMTEST_BROWSER)[0]
ini_path = os.path.join(os.path.dirname(exe_path), "platform.ini")
# Extract the first numeric part before any dot (e.g. "Milestone=102.15.1" → 102)
m = re.search(r"^Milestone=([^\n\r]+)", open(ini_path).read(), re.MULTILINE)
milestone = m.group(1).strip()
version = int(re.match(r"(\d+)", milestone).group(1))
# On Nightly and BEta, e.g. 145.0a1, pretend it to still mean version 144,
# since it is a pre-release version
if any(c in milestone for c in ("a", "b")):
version -= 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use firefox --version for this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

firefox --version seems to be a linux thing. It doesn't exist on Windows.

return version


no_swiftshader = skip_if_simple('not compatible with swiftshader', is_swiftshader)

no_chrome = skip_if('no_chrome', lambda _: is_chrome(), 'chrome is not supported')
Expand Down Expand Up @@ -214,25 +231,30 @@ def decorated(self, *args, **kwargs):


def webgl2_disabled():
return os.getenv('EMTEST_LACKS_WEBGL2') or os.getenv('EMTEST_LACKS_GRAPHICS_HARDWARE')
return os.getenv('EMTEST_LACKS_WEBGL2') or os.getenv('EMTEST_LACKS_GRAPHICS_HARDWARE') or current_browser_lacks_feature(Feature.WEBGL2)


def webgpu_disabled():
return os.getenv('EMTEST_LACKS_WEBGPU') or os.getenv('EMTEST_LACKS_GRAPHICS_HARDWARE')
return os.getenv('EMTEST_LACKS_WEBGPU') or os.getenv('EMTEST_LACKS_GRAPHICS_HARDWARE') or current_browser_lacks_feature(Feature.WEBGPU)


def current_browser_lacks_feature(feature):
min_required = min_browser_versions[feature]
return get_firefox_version() < min_required['firefox'] or get_safari_version() < min_required['safari']


requires_graphics_hardware = skipExecIf(os.getenv('EMTEST_LACKS_GRAPHICS_HARDWARE'), 'This test requires graphics hardware')
requires_webgl2 = unittest.skipIf(webgl2_disabled(), "This test requires WebGL2 to be available")
requires_webgpu = unittest.skipIf(webgpu_disabled(), "This test requires WebGPU to be available")
requires_sound_hardware = skipExecIf(os.getenv('EMTEST_LACKS_SOUND_HARDWARE'), 'This test requires sound hardware')
requires_microphone_access = skipExecIf(os.getenv('EMTEST_LACKS_MICROPHONE_ACCESS'), 'This test accesses microphone, which may need accepting a user prompt to enable it.')
requires_offscreen_canvas = unittest.skipIf(os.getenv('EMTEST_LACKS_OFFSCREEN_CANVAS'), 'This test requires a browser with OffscreenCanvas')
requires_es6_workers = unittest.skipIf(os.getenv('EMTEST_LACKS_ES6_WORKERS'), 'This test requires a browser with ES6 Module Workers support')
requires_growable_arraybuffers = unittest.skipIf(os.getenv('EMTEST_LACKS_GROWABLE_ARRAYBUFFERS'), 'This test requires a browser that supports growable ArrayBuffers')
requires_offscreen_canvas = unittest.skipIf(os.getenv('EMTEST_LACKS_OFFSCREEN_CANVAS') or current_browser_lacks_feature(Feature.OFFSCREENCANVAS_SUPPORT), 'This test requires a browser with OffscreenCanvas')
requires_es6_workers = unittest.skipIf(os.getenv('EMTEST_LACKS_ES6_WORKERS') or current_browser_lacks_feature(Feature.WORKER_ES6_MODULES), 'This test requires a browser with ES6 Module Workers support')
requires_growable_arraybuffers = unittest.skipIf(os.getenv('EMTEST_LACKS_GROWABLE_ARRAYBUFFERS') or current_browser_lacks_feature(Feature.GROWABLE_ARRAYBUFFERS), 'This test requires a browser that supports growable ArrayBuffers')
# N.b. not all SharedArrayBuffer requiring tests are annotated with this decorator, since at this point there are so many of such tests.
# As a middle ground, if a test has a name 'thread' or 'wasm_worker' in it, then it does not need decorating. To run all single-threaded tests in
# the suite, one can run "EMTEST_LACKS_SHARED_ARRAY_BUFFER=1 test/runner browser skip:browser.test_*thread* skip:browser.test_*wasm_worker* skip:browser.test_*audio_worklet*"
requires_shared_array_buffer = unittest.skipIf(os.getenv('EMTEST_LACKS_SHARED_ARRAY_BUFFER'), 'This test requires a browser with SharedArrayBuffer support')
requires_shared_array_buffer = unittest.skipIf(os.getenv('EMTEST_LACKS_SHARED_ARRAY_BUFFER') or current_browser_lacks_feature(Feature.THREADS), 'This test requires a browser with SharedArrayBuffer support')


class browser(BrowserCore):
Expand Down
23 changes: 23 additions & 0 deletions tools/feature_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class Feature(IntEnum):
OFFSCREENCANVAS_SUPPORT = auto()
WASM_LEGACY_EXCEPTIONS = auto()
WASM_EXCEPTIONS = auto()
WEBGL2 = auto()
WEBGPU = auto()
GROWABLE_ARRAYBUFFERS = auto()


disable_override_features = set()
Expand Down Expand Up @@ -90,6 +93,18 @@ class Feature(IntEnum):
'safari': UNSUPPORTED,
'node': 230000,
},
Feature.WEBGL2: {
'chrome': 56,
'firefox': 51,
'safari': 150000,
'node': UNSUPPORTED,
},
Feature.WEBGPU: {
'chrome': 113,
'firefox': 141,
'safari': 260000,
'node': UNSUPPORTED,
},
# https://caniuse.com/mdn-api_worker_worker_ecmascript_modules: The ability to
# call new Worker(url, { type: 'module' });
Feature.WORKER_ES6_MODULES: {
Expand Down Expand Up @@ -127,6 +142,14 @@ class Feature(IntEnum):
# Node.js 26)
'node': 240000,
},
# Growable SharedArrayBuffers improves memory growth feature in multithreaded
# builds by avoiding need to poll resizes to ArrayBuffer views in Workers.
Feature.GROWABLE_ARRAYBUFFERS: {
'chrome': 111,
'firefox': 128,
'safari': 160400,
'node': 200000,
},
}

# Static assertion to check that we actually need each of the above feature flags
Expand Down