Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
21 changes: 14 additions & 7 deletions bzt/modules/javascript.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,14 +538,18 @@ def check_if_installed(self):
if not super().check_if_installed():
return False
# Check if installed version is expected version if we force version
if os.environ.get("PLAYWRIGHT_TEST_PACKAGE_FORCED_VERSION", None) is None:
forced_version = os.environ.get("PLAYWRIGHT_TEST_PACKAGE_FORCED_VERSION", None)
if forced_version is None:
# Not forcing version, any installed is good
return True

cmdline = [self.npm.tool_path, "list"]
# `npx --no` reads the locally-installed version without fetching from the
# registry. Mirrors the freeze step in taurus-cloud Dockerfile-reduced.
cmdline = ["npx", "--no", "--", "@playwright/test", "--version"]
try:
out, _ = self.call(cmdline)
version_changed = self.PACKAGE_NAME not in out
out, _ = self.call(cmdline, cwd=self.tools_dir)
installed = (out or "").strip().split()[-1] if (out or "").strip() else ""
version_changed = installed != forced_version
Comment thread
henrychv marked this conversation as resolved.
if version_changed:
self.log.warning("Frozen version not found in installed packages, will re-install %s", self.PACKAGE_NAME)
return not version_changed
Expand Down Expand Up @@ -576,10 +580,13 @@ def install(self):
package_name = "playwright" if frozen_version is None else "playwright@" + frozen_version
version_changed = False
if frozen_version:
cmdline = ["npm", "list"]
# `npx --no` reads the locally-installed version without fetching from the
# registry. Mirrors the freeze step in taurus-cloud Dockerfile-reduced.
cmdline = ["npx", "--no", "--", "playwright", "--version"]
try:
out, _ = self.call(cmdline)
version_changed = package_name not in out
out, _ = self.call(cmdline, cwd=self.tools_dir)
installed = (out or "").strip().split()[-1] if (out or "").strip() else ""
version_changed = installed != frozen_version
if version_changed:
self.log.warning("Frozen version not found in installed packages, will re-install %s", package_name)
except CALL_PROBLEMS as exc:
Expand Down
49 changes: 27 additions & 22 deletions tests/unit/modules/_selenium/test_javascript.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,14 +588,17 @@ def test_playwright_install_non_linux(self, mock_is_linux):
def test_playwright_install_frozen_version(self):
"""Test that Playwright install is skipped when frozen version is already installed"""
playwright = PLAYWRIGHT(tools_dir=self.tools_dir)
# npm list returns output containing the frozen version
playwright.call = MagicMock(return_value=("playwright@1.40.0 node_modules/playwright", ""))
# `npx --no -- playwright --version` reports the installed version, matching the frozen one
playwright.call = MagicMock(return_value=("Version 1.40.0\n", ""))

with patch.dict(os.environ, {'PLAYWRIGHT_PACKAGE_FORCED_VERSION': '1.40.0'}):
playwright.install()

# Should call npm list once to check the installed version
playwright.call.assert_called_once_with(["npm", "list"])
# Should call npx --no -- playwright --version once to check the installed version
playwright.call.assert_called_once_with(
["npx", "--no", "--", "playwright", "--version"],
cwd=self.tools_dir,
)

@patch('bzt.modules.javascript.is_linux')
def test_playwright_install_frozen_version_changed(self, mock_is_linux):
Expand All @@ -605,15 +608,16 @@ def test_playwright_install_frozen_version_changed(self, mock_is_linux):
playwright = PLAYWRIGHT(tools_dir=self.tools_dir)
os.makedirs(self.tools_dir, exist_ok=True)

# npm list returns a different (old) version — frozen version NOT present
playwright.call = MagicMock(return_value=("playwright@1.39.0 node_modules/playwright", ""))
# Probe reports a different (old) version — frozen version mismatch
playwright.call = MagicMock(side_effect=[("Version 1.39.0\n", ""), ("", "")])

with patch.dict(os.environ, {'PLAYWRIGHT_PACKAGE_FORCED_VERSION': '1.40.0'}):
playwright.install()

# First call: npm list version check
# First call: version probe
first_call_args = playwright.call.call_args_list[0][0][0]
self.assertEqual(first_call_args, ["npm", "list"])
self.assertEqual(first_call_args, ["npx", "--no", "--", "playwright", "--version"])
self.assertEqual(playwright.call.call_args_list[0][1].get('cwd'), self.tools_dir)

# Second call: npx playwright@1.40.0 install --with-deps
self.assertEqual(playwright.call.call_count, 2)
Expand All @@ -624,22 +628,22 @@ def test_playwright_install_frozen_version_changed(self, mock_is_linux):
self.assertIn("--with-deps", second_call_args)

@patch('bzt.modules.javascript.is_linux')
def test_playwright_install_frozen_version_npm_list_oserror(self, mock_is_linux):
"""Test that Playwright re-installs when npm list raises OSError during version check"""
def test_playwright_install_frozen_version_probe_oserror(self, mock_is_linux):
"""Test that Playwright re-installs when the version probe raises OSError"""
mock_is_linux.return_value = False

playwright = PLAYWRIGHT(tools_dir=self.tools_dir)
os.makedirs(self.tools_dir, exist_ok=True)

# First call (npm list) raises OSError; second call is the actual install
playwright.call = MagicMock(side_effect=[OSError("npm list failed"), ("", "")])
# First call (version probe) raises OSError; second call is the actual install
playwright.call = MagicMock(side_effect=[OSError("npx probe failed"), ("", "")])

with patch.dict(os.environ, {'PLAYWRIGHT_PACKAGE_FORCED_VERSION': '1.40.0'}):
playwright.install()

self.assertEqual(playwright.call.call_count, 2)
first_call_args = playwright.call.call_args_list[0][0][0]
self.assertEqual(first_call_args, ["npm", "list"])
self.assertEqual(first_call_args, ["npx", "--no", "--", "playwright", "--version"])

second_call_args = playwright.call.call_args_list[1][0][0]
self.assertIn("npx", second_call_args)
Expand Down Expand Up @@ -737,7 +741,7 @@ def _create_package(self):
)

def test_check_if_installed_super_returns_false(self):
"""When the parent require() check fails, return False without calling npm list"""
"""When the parent require() check fails, return False without probing version"""
pkg = self._create_package()
pkg.call = MagicMock(return_value=("", ""))

Expand All @@ -747,7 +751,7 @@ def test_check_if_installed_super_returns_false(self):
pkg.call.assert_called_once()

def test_check_if_installed_no_forced_version(self):
"""When no forced version is set, any installed version is acceptable and npm list is not called"""
"""When no forced version is set, any installed version is acceptable and the probe is not called"""
pkg = self._create_package()
pkg.call = MagicMock(return_value=("@playwright/test is installed", ""))

Expand All @@ -765,7 +769,7 @@ def test_check_if_installed_forced_version_correct(self):
pkg = self._create_package()
pkg.call = MagicMock(side_effect=[
("@playwright/test is installed", ""),
("@playwright/test@1.40.0 node_modules/@playwright/test", ""),
("Version 1.40.0\n", ""),
])

with patch.object(PlaywrightTestPackage, 'PACKAGE_NAME', '@playwright/test@1.40.0'):
Expand All @@ -775,14 +779,15 @@ def test_check_if_installed_forced_version_correct(self):
self.assertTrue(result)
self.assertEqual(pkg.call.call_count, 2)
second_call_args = pkg.call.call_args_list[1][0][0]
self.assertEqual(second_call_args, [self.npm_mock.tool_path, "list"])
self.assertEqual(second_call_args, ["npx", "--no", "--", "@playwright/test", "--version"])
Comment thread
henrychv marked this conversation as resolved.
self.assertEqual(pkg.call.call_args_list[1][1].get('cwd'), self.tools_dir)

def test_check_if_installed_forced_version_mismatch(self):
"""When forced version is not present in npm list output, return False"""
"""When the probed version differs from the forced version, return False"""
pkg = self._create_package()
pkg.call = MagicMock(side_effect=[
("@playwright/test is installed", ""),
("@playwright/test@1.39.0 node_modules/@playwright/test", ""),
("Version 1.39.0\n", ""),
])

with patch.object(PlaywrightTestPackage, 'PACKAGE_NAME', '@playwright/test@1.40.0'):
Expand All @@ -792,12 +797,12 @@ def test_check_if_installed_forced_version_mismatch(self):
self.assertFalse(result)
self.assertEqual(pkg.call.call_count, 2)

def test_check_if_installed_npm_list_call_fails(self):
"""When npm list raises an OSError, return False"""
def test_check_if_installed_version_probe_fails(self):
"""When the version probe raises an OSError, return False"""
pkg = self._create_package()
pkg.call = MagicMock(side_effect=[
("@playwright/test is installed", ""),
OSError("npm list failed"),
OSError("npx probe failed"),
])

with patch.dict(os.environ, {'PLAYWRIGHT_TEST_PACKAGE_FORCED_VERSION': '1.40.0'}):
Expand Down
Loading