From 95b78e084d948491f50696aed9e3124f9860006d Mon Sep 17 00:00:00 2001 From: Jaromir Obr Date: Fri, 30 Jan 2026 11:55:37 +0100 Subject: [PATCH 1/2] fix: support Playwright 1.58+ output format in `codeceptjs info` Playwright 1.58 changed the output format of `npx playwright install --dry-run`: - Old format: "browser: chromium version 143.0.7499.4" - New format: "Chrome for Testing 145.0.7632.6 (playwright chromium v1208)" Updated the regex to handle both formats while excluding chromium-headless-shell. Fixes #5422 Co-Authored-By: Claude Opus 4.5 --- lib/command/info.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/command/info.js b/lib/command/info.js index 05dff5bf9..79a2231dc 100644 --- a/lib/command/info.js +++ b/lib/command/info.js @@ -7,16 +7,18 @@ const { execSync } = require('child_process') async function getPlaywrightBrowsers() { try { - const regex = /(chromium|firefox|webkit)\s+version\s+([\d.]+)/gi + // Unified regex for both formats (excludes chromium-headless-shell): + // - 1.58+: "Firefox 146.0.1 (playwright firefox v1509)" + // - 1.57: "browser: firefox version 144.0.2" + const regex = /(?:([\d.]+)\s+\(playwright\s+(chromium|firefox|webkit)\s)|(?:browser:\s*(chromium|firefox|webkit)\s+version\s+([\d.]+))/gi let versions = [] const info = execSync('npx playwright install --dry-run').toString().trim() const matches = [...info.matchAll(regex)] - matches.forEach(match => { - const browser = match[1] - const version = match[2] + const browser = match[2] || match[3] + const version = match[1] || match[4] versions.push(`${browser}: ${version}`) }) From 23f77e73ffd5d813cf6e9b90c65e68768841ff95 Mon Sep 17 00:00:00 2001 From: Jaromir Obr Date: Tue, 3 Feb 2026 14:20:54 +0100 Subject: [PATCH 2/2] test: add unit tests for parsePlaywrightBrowsers regex Extract parsePlaywrightBrowsers function and add unit tests to verify both old (Playwright < 1.58) and new (1.58+) output formats are parsed correctly, and that chromium-headless-shell is excluded. Co-Authored-By: Claude Opus 4.5 --- lib/command/info.js | 34 ++++++------ test/unit/command/info_test.js | 98 ++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 test/unit/command/info_test.js diff --git a/lib/command/info.js b/lib/command/info.js index 79a2231dc..b8741cc05 100644 --- a/lib/command/info.js +++ b/lib/command/info.js @@ -5,24 +5,26 @@ const Codecept = require('../codecept') const output = require('../output') const { execSync } = require('child_process') +// Unified regex for both formats (excludes chromium-headless-shell): +// - 1.58+: "Firefox 146.0.1 (playwright firefox v1509)" +// - 1.57: "browser: firefox version 144.0.2" +const playwrightBrowserRegex = /(?:([\d.]+)\s+\(playwright\s+(chromium|firefox|webkit)\s)|(?:browser:\s*(chromium|firefox|webkit)\s+version\s+([\d.]+))/gi + +function parsePlaywrightBrowsers(output) { + const versions = [] + const matches = [...output.matchAll(playwrightBrowserRegex)] + matches.forEach(match => { + const browser = match[2] || match[3] + const version = match[1] || match[4] + versions.push(`${browser}: ${version}`) + }) + return versions.join(', ') +} + async function getPlaywrightBrowsers() { try { - // Unified regex for both formats (excludes chromium-headless-shell): - // - 1.58+: "Firefox 146.0.1 (playwright firefox v1509)" - // - 1.57: "browser: firefox version 144.0.2" - const regex = /(?:([\d.]+)\s+\(playwright\s+(chromium|firefox|webkit)\s)|(?:browser:\s*(chromium|firefox|webkit)\s+version\s+([\d.]+))/gi - let versions = [] - const info = execSync('npx playwright install --dry-run').toString().trim() - - const matches = [...info.matchAll(regex)] - matches.forEach(match => { - const browser = match[2] || match[3] - const version = match[1] || match[4] - versions.push(`${browser}: ${version}`) - }) - - return versions.join(', ') + return parsePlaywrightBrowsers(info) } catch (err) { return 'Playwright not installed' } @@ -75,6 +77,8 @@ module.exports = async function (path) { output.print('***************************************') } +module.exports.parsePlaywrightBrowsers = parsePlaywrightBrowsers + module.exports.getMachineInfo = async () => { const info = { nodeInfo: await envinfo.helpers.getNodeInfo(), diff --git a/test/unit/command/info_test.js b/test/unit/command/info_test.js new file mode 100644 index 000000000..9e3970439 --- /dev/null +++ b/test/unit/command/info_test.js @@ -0,0 +1,98 @@ +let expect +import('chai').then(chai => { + expect = chai.expect +}) + +const { parsePlaywrightBrowsers } = require('../../../lib/command/info') + +describe('info command', () => { + describe('parsePlaywrightBrowsers', () => { + describe('old format (Playwright < 1.58)', () => { + const oldFormatOutput = `browser: chromium version 140.0.7339.186 +browser: chromium-headless-shell version 140.0.7339.186 +browser: firefox version 141.0 +browser: webkit version 26.0` + + it('should parse chromium version', () => { + const result = parsePlaywrightBrowsers(oldFormatOutput) + expect(result).to.include('chromium: 140.0.7339.186') + }) + + it('should parse firefox version', () => { + const result = parsePlaywrightBrowsers(oldFormatOutput) + expect(result).to.include('firefox: 141.0') + }) + + it('should parse webkit version', () => { + const result = parsePlaywrightBrowsers(oldFormatOutput) + expect(result).to.include('webkit: 26.0') + }) + + it('should exclude chromium-headless-shell', () => { + const result = parsePlaywrightBrowsers(oldFormatOutput) + expect(result).to.not.include('chromium-headless-shell') + }) + + it('should return all three browsers', () => { + const result = parsePlaywrightBrowsers(oldFormatOutput) + expect(result).to.equal('chromium: 140.0.7339.186, firefox: 141.0, webkit: 26.0') + }) + }) + + describe('new format (Playwright 1.58+)', () => { + const newFormatOutput = `Chrome for Testing 145.0.7632.6 (playwright chromium v1208) +Chromium Headless Shell 145.0.7632.6 (playwright build v1208) +Firefox 146.0.1 (playwright firefox v1509) +Webkit 18.4 (playwright webkit v2140)` + + it('should parse chromium version', () => { + const result = parsePlaywrightBrowsers(newFormatOutput) + expect(result).to.include('chromium: 145.0.7632.6') + }) + + it('should parse firefox version', () => { + const result = parsePlaywrightBrowsers(newFormatOutput) + expect(result).to.include('firefox: 146.0.1') + }) + + it('should parse webkit version', () => { + const result = parsePlaywrightBrowsers(newFormatOutput) + expect(result).to.include('webkit: 18.4') + }) + + it('should exclude Chromium Headless Shell', () => { + const result = parsePlaywrightBrowsers(newFormatOutput) + expect(result).to.not.include('Headless') + }) + + it('should return all three browsers', () => { + const result = parsePlaywrightBrowsers(newFormatOutput) + expect(result).to.equal('chromium: 145.0.7632.6, firefox: 146.0.1, webkit: 18.4') + }) + }) + + describe('mixed/edge cases', () => { + it('should handle empty input', () => { + const result = parsePlaywrightBrowsers('') + expect(result).to.equal('') + }) + + it('should handle input with no matching browsers', () => { + const result = parsePlaywrightBrowsers('some random text without browser info') + expect(result).to.equal('') + }) + + it('should handle case insensitivity for old format', () => { + const input = 'browser: CHROMIUM version 100.0.0' + const result = parsePlaywrightBrowsers(input) + expect(result).to.equal('CHROMIUM: 100.0.0') + }) + + it('should handle case insensitivity for new format', () => { + const input = 'Chrome 100.0.0 (playwright CHROMIUM v1234)' + const result = parsePlaywrightBrowsers(input) + expect(result).to.equal('CHROMIUM: 100.0.0') + }) + }) + }) +})