diff --git a/.circleci/src/pipeline/@pipeline.yml b/.circleci/src/pipeline/@pipeline.yml index 5420f375817..3262a5dd0ed 100644 --- a/.circleci/src/pipeline/@pipeline.yml +++ b/.circleci/src/pipeline/@pipeline.yml @@ -17,7 +17,7 @@ ubuntu-2004-current: &ubuntu-2004-current ubuntu-2004:2024.11.1 ubuntu-2004-older: &ubuntu-2004-older ubuntu-2004:2024.05.1 orbs: - browser-tools: circleci/browser-tools@2.1.1 + browser-tools: circleci/browser-tools@2.3.1 defaults: &defaults parallelism: 1 @@ -563,6 +563,7 @@ commands: # https://www.ubuntuupdates.org/package/google_chrome/stable/main/base/google-chrome-stable channel: << parameters.google-chrome-channel >> chrome_version: << parameters.google-chrome-version >> + replace_existing: true - when: condition: equal: [ 'beta', << parameters.google-chrome-channel>> ] @@ -1786,7 +1787,7 @@ jobs: source ./scripts/ensure-node.sh yarn lerna run types - sanitize-verify-and-store-mocha-results: - expectedResultCount: 10 + expectedResultCount: 9 verify-release-readiness: <<: *defaults diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 6e4ab04ffe5..894099b1d0e 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,4 +1,12 @@ +## 15.4.1 + +_Released 10/21/2025 (PENDING)_ + +**Misc:** + +Browser detection in Cypress now always prefers 64-bit browser installs to 32-bit browser installs. Addressed in [#32656](https://github.com/cypress-io/cypress/pull/32656). + ## 15.4.0 _Released 10/7/2025_ diff --git a/guides/esm-migration.md b/guides/esm-migration.md index f9b2cd4905a..0f8d2597307 100644 --- a/guides/esm-migration.md +++ b/guides/esm-migration.md @@ -98,7 +98,7 @@ When migrating some of these projects away from the `ts-node` entry [see `@packa - [ ] packages/https-proxy - [x] packages/electron ✅ **COMPLETED** - [x] packages/icons ✅ **COMPLETED** -- [ ] packages/launcher +- [x] packages/launcher ✅ **COMPLETED** - [ ] packages/net-stubbing - [x] packages/network ✅ **COMPLETED** - [ ] packages/packherd-require diff --git a/packages/launcher/__snapshots__/browsers_spec.ts.js b/packages/launcher/__snapshots__/browsers_spec.ts.js deleted file mode 100644 index b44419587a1..00000000000 --- a/packages/launcher/__snapshots__/browsers_spec.ts.js +++ /dev/null @@ -1,123 +0,0 @@ -exports['browsers returns the expected list of browsers 1'] = [ - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome', - 'versionRegex': {}, - 'binary': [ - 'google-chrome', - 'chrome', - 'google-chrome-stable', - ], - }, - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'beta', - 'displayName': 'Chrome Beta', - 'versionRegex': {}, - 'binary': 'google-chrome-beta', - }, - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'canary', - 'displayName': 'Chrome Canary', - 'versionRegex': {}, - 'binary': 'google-chrome-canary', - }, - { - 'name': 'chrome-for-testing', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome for Testing', - 'versionRegex': {}, - 'binary': 'chrome', - }, - { - 'name': 'chromium', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chromium', - 'versionRegex': {}, - 'binary': [ - 'chromium-browser', - 'chromium', - ], - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'stable', - 'displayName': 'Firefox', - 'versionRegex': {}, - 'binary': 'firefox', - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'dev', - 'displayName': 'Firefox Developer Edition', - 'versionRegex': {}, - 'binary': [ - 'firefox-developer-edition', - 'firefox', - ], - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'nightly', - 'displayName': 'Firefox Nightly', - 'versionRegex': {}, - 'binary': [ - 'firefox-nightly', - 'firefox-trunk', - ], - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Edge', - 'versionRegex': {}, - 'binary': [ - 'edge', - 'microsoft-edge', - ], - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'beta', - 'displayName': 'Edge Beta', - 'versionRegex': {}, - 'binary': [ - 'edge-beta', - 'microsoft-edge-beta', - ], - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'canary', - 'displayName': 'Edge Canary', - 'versionRegex': {}, - 'binary': [ - 'edge-canary', - 'microsoft-edge-canary', - ], - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'dev', - 'displayName': 'Edge Dev', - 'versionRegex': {}, - 'binary': [ - 'edge-dev', - 'microsoft-edge-dev', - ], - }, -] diff --git a/packages/launcher/__snapshots__/darwin_spec.ts.js b/packages/launcher/__snapshots__/darwin_spec.ts.js deleted file mode 100644 index 8b20e11f91d..00000000000 --- a/packages/launcher/__snapshots__/darwin_spec.ts.js +++ /dev/null @@ -1,219 +0,0 @@ -exports['darwin browser detection detects browsers as expected 1'] = [ - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome', - 'versionRegex': {}, - 'binary': [ - 'google-chrome', - 'chrome', - 'google-chrome-stable', - ], - 'path': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Google Chrome.app', - 'executable': 'Contents/MacOS/Google Chrome', - 'bundleId': 'com.google.Chrome', - 'versionProperty': 'KSVersion', - }, - }, - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'beta', - 'displayName': 'Chrome Beta', - 'versionRegex': {}, - 'binary': 'google-chrome-beta', - 'path': '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Google Chrome Beta.app', - 'executable': 'Contents/MacOS/Google Chrome Beta', - 'bundleId': 'com.google.Chrome.beta', - 'versionProperty': 'KSVersion', - }, - }, - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'canary', - 'displayName': 'Chrome Canary', - 'versionRegex': {}, - 'binary': 'google-chrome-canary', - 'path': '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Google Chrome Canary.app', - 'executable': 'Contents/MacOS/Google Chrome Canary', - 'bundleId': 'com.google.Chrome.canary', - 'versionProperty': 'KSVersion', - }, - }, - { - 'name': 'chrome-for-testing', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome for Testing', - 'versionRegex': {}, - 'binary': 'chrome', - 'path': '/Applications/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Google Chrome for Testing.app', - 'executable': 'Contents/MacOS/Google Chrome for Testing', - 'bundleId': 'com.google.chrome.for.testing', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'chromium', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chromium', - 'versionRegex': {}, - 'binary': [ - 'chromium-browser', - 'chromium', - ], - 'path': '/Applications/Chromium.app/Contents/MacOS/Chromium', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Chromium.app', - 'executable': 'Contents/MacOS/Chromium', - 'bundleId': 'org.chromium.Chromium', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'stable', - 'displayName': 'Firefox', - 'versionRegex': {}, - 'binary': 'firefox', - 'path': '/Applications/Firefox.app/Contents/MacOS/firefox', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Firefox.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.firefox', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'dev', - 'displayName': 'Firefox Developer Edition', - 'versionRegex': {}, - 'binary': [ - 'firefox-developer-edition', - 'firefox', - ], - 'path': '/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Firefox Developer Edition.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.firefoxdeveloperedition', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'nightly', - 'displayName': 'Firefox Nightly', - 'versionRegex': {}, - 'binary': [ - 'firefox-nightly', - 'firefox-trunk', - ], - 'path': '/Applications/Firefox Nightly.app/Contents/MacOS/firefox', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Firefox Nightly.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.nightly', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Edge', - 'versionRegex': {}, - 'binary': [ - 'edge', - 'microsoft-edge', - ], - 'path': '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Microsoft Edge.app', - 'executable': 'Contents/MacOS/Microsoft Edge', - 'bundleId': 'com.microsoft.Edge', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'beta', - 'displayName': 'Edge Beta', - 'versionRegex': {}, - 'binary': [ - 'edge-beta', - 'microsoft-edge-beta', - ], - 'path': '/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Microsoft Edge Beta.app', - 'executable': 'Contents/MacOS/Microsoft Edge Beta', - 'bundleId': 'com.microsoft.Edge.Beta', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'canary', - 'displayName': 'Edge Canary', - 'versionRegex': {}, - 'binary': [ - 'edge-canary', - 'microsoft-edge-canary', - ], - 'path': '/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Microsoft Edge Canary.app', - 'executable': 'Contents/MacOS/Microsoft Edge Canary', - 'bundleId': 'com.microsoft.Edge.Canary', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'dev', - 'displayName': 'Edge Dev', - 'versionRegex': {}, - 'binary': [ - 'edge-dev', - 'microsoft-edge-dev', - ], - 'path': '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev', - 'version': 'someVersion', - 'findAppParams': { - 'appName': 'Microsoft Edge Dev.app', - 'executable': 'Contents/MacOS/Microsoft Edge Dev', - 'bundleId': 'com.microsoft.Edge.Dev', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, -] diff --git a/packages/launcher/__snapshots__/windows_spec.ts.js b/packages/launcher/__snapshots__/windows_spec.ts.js deleted file mode 100644 index e6e106b341d..00000000000 --- a/packages/launcher/__snapshots__/windows_spec.ts.js +++ /dev/null @@ -1,403 +0,0 @@ -exports['windows browser detection detects browsers as expected 1'] = [ - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome', - 'versionRegex': {}, - 'binary': [ - 'google-chrome', - 'chrome', - 'google-chrome-stable', - ], - 'path': 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe', - 'version': '1.2.3', - 'findAppParams': { - 'appName': 'Google Chrome.app', - 'executable': 'Contents/MacOS/Google Chrome', - 'bundleId': 'com.google.Chrome', - 'versionProperty': 'KSVersion', - }, - }, - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'beta', - 'displayName': 'Chrome Beta', - 'versionRegex': {}, - 'binary': 'google-chrome-beta', - 'path': 'C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe', - 'version': '6.7.8', - 'findAppParams': { - 'appName': 'Google Chrome Beta.app', - 'executable': 'Contents/MacOS/Google Chrome Beta', - 'bundleId': 'com.google.Chrome.beta', - 'versionProperty': 'KSVersion', - }, - }, - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'canary', - 'displayName': 'Chrome Canary', - 'versionRegex': {}, - 'binary': 'google-chrome-canary', - 'path': 'C:/Users/flotwig/AppData/Local/Google/Chrome SxS/Application/chrome.exe', - 'version': '3.4.5', - 'findAppParams': { - 'appName': 'Google Chrome Canary.app', - 'executable': 'Contents/MacOS/Google Chrome Canary', - 'bundleId': 'com.google.Chrome.canary', - 'versionProperty': 'KSVersion', - }, - }, - { - 'name': 'chrome-for-testing', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome for Testing', - 'versionRegex': {}, - 'binary': 'chrome', - 'path': 'C:/Program Files/Google/Chrome for Testing/chrome.exe', - 'version': '1.2.3', - 'findAppParams': { - 'appName': 'Google Chrome for Testing.app', - 'executable': 'Contents/MacOS/Google Chrome for Testing', - 'bundleId': 'com.google.chrome.for.testing', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'chromium', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chromium', - 'versionRegex': {}, - 'binary': [ - 'chromium-browser', - 'chromium', - ], - 'path': 'C:/Program Files (x86)/Google/chrome-win32/chrome.exe', - 'version': '2.3.4', - 'findAppParams': { - 'appName': 'Chromium.app', - 'executable': 'Contents/MacOS/Chromium', - 'bundleId': 'org.chromium.Chromium', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'stable', - 'displayName': 'Firefox', - 'versionRegex': {}, - 'binary': 'firefox', - 'path': 'C:/Program Files/Mozilla Firefox/firefox.exe', - 'version': '72', - 'findAppParams': { - 'appName': 'Firefox.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.firefox', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'dev', - 'displayName': 'Firefox Developer Edition', - 'versionRegex': {}, - 'binary': [ - 'firefox-developer-edition', - 'firefox', - ], - 'path': 'C:/Program Files (x86)/Firefox Developer Edition/firefox.exe', - 'version': '73', - 'findAppParams': { - 'appName': 'Firefox Developer Edition.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.firefoxdeveloperedition', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'nightly', - 'displayName': 'Firefox Nightly', - 'versionRegex': {}, - 'binary': [ - 'firefox-nightly', - 'firefox-trunk', - ], - 'path': 'C:/Program Files/Firefox Nightly/firefox.exe', - 'version': '74', - 'findAppParams': { - 'appName': 'Firefox Nightly.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.nightly', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Edge', - 'versionRegex': {}, - 'binary': [ - 'edge', - 'microsoft-edge', - ], - 'path': 'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe', - 'version': '11', - 'findAppParams': { - 'appName': 'Microsoft Edge.app', - 'executable': 'Contents/MacOS/Microsoft Edge', - 'bundleId': 'com.microsoft.Edge', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'beta', - 'displayName': 'Edge Beta', - 'versionRegex': {}, - 'binary': [ - 'edge-beta', - 'microsoft-edge-beta', - ], - 'path': 'C:/Program Files (x86)/Microsoft/Edge Beta/Application/msedge.exe', - 'version': '12', - 'findAppParams': { - 'appName': 'Microsoft Edge Beta.app', - 'executable': 'Contents/MacOS/Microsoft Edge Beta', - 'bundleId': 'com.microsoft.Edge.Beta', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'canary', - 'displayName': 'Edge Canary', - 'versionRegex': {}, - 'binary': [ - 'edge-canary', - 'microsoft-edge-canary', - ], - 'path': 'C:/Users/flotwig/AppData/Local/Microsoft/Edge SxS/Application/msedge.exe', - 'version': '14', - 'findAppParams': { - 'appName': 'Microsoft Edge Canary.app', - 'executable': 'Contents/MacOS/Microsoft Edge Canary', - 'bundleId': 'com.microsoft.Edge.Canary', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'edge', - 'family': 'chromium', - 'channel': 'dev', - 'displayName': 'Edge Dev', - 'versionRegex': {}, - 'binary': [ - 'edge-dev', - 'microsoft-edge-dev', - ], - 'path': 'C:/Program Files (x86)/Microsoft/Edge Dev/Application/msedge.exe', - 'version': '13', - 'findAppParams': { - 'appName': 'Microsoft Edge Dev.app', - 'executable': 'Contents/MacOS/Microsoft Edge Dev', - 'bundleId': 'com.microsoft.Edge.Dev', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, -] - -exports['windows browser detection detects Chrome Beta 64-bit install 1'] = [ - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'beta', - 'displayName': 'Chrome Beta', - 'versionRegex': {}, - 'binary': 'google-chrome-beta', - 'path': 'C:/Program Files/Google/Chrome Beta/Application/chrome.exe', - 'version': '9.0.1', - 'findAppParams': { - 'appName': 'Google Chrome Beta.app', - 'executable': 'Contents/MacOS/Google Chrome Beta', - 'bundleId': 'com.google.Chrome.beta', - 'versionProperty': 'KSVersion', - }, - }, -] - -exports['windows browser detection detects Chrome 64-bit install 1'] = [ - { - 'name': 'chrome', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome', - 'versionRegex': {}, - 'binary': [ - 'google-chrome', - 'chrome', - 'google-chrome-stable', - ], - 'path': 'C:/Program Files/Google/Chrome/Application/chrome.exe', - 'version': '4.4.4', - 'findAppParams': { - 'appName': 'Google Chrome.app', - 'executable': 'Contents/MacOS/Google Chrome', - 'bundleId': 'com.google.Chrome', - 'versionProperty': 'KSVersion', - }, - }, -] - -exports['windows browser detection detects Chrome for Testing 32-bit install 1'] = [ - { - 'name': 'chrome-for-testing', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chrome for Testing', - 'versionRegex': {}, - 'binary': 'chrome', - 'path': 'C:/Program Files (x86)/Google/Chrome for Testing/chrome.exe', - 'version': '5.5.5', - 'findAppParams': { - 'appName': 'Google Chrome for Testing.app', - 'executable': 'Contents/MacOS/Google Chrome for Testing', - 'bundleId': 'com.google.chrome.for.testing', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, -] - -exports['windows browser detection detects Firefox local installs 1'] = [ - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'stable', - 'displayName': 'Firefox', - 'versionRegex': {}, - 'binary': 'firefox', - 'path': 'C:/Users/flotwig/AppData/Local/Mozilla Firefox/firefox.exe', - 'version': '100', - 'findAppParams': { - 'appName': 'Firefox.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.firefox', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'dev', - 'displayName': 'Firefox Developer Edition', - 'versionRegex': {}, - 'binary': [ - 'firefox-developer-edition', - 'firefox', - ], - 'path': 'C:/Users/flotwig/AppData/Local/Firefox Developer Edition/firefox.exe', - 'version': '300', - 'findAppParams': { - 'appName': 'Firefox Developer Edition.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.firefoxdeveloperedition', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, - { - 'name': 'firefox', - 'family': 'firefox', - 'channel': 'nightly', - 'displayName': 'Firefox Nightly', - 'versionRegex': {}, - 'binary': [ - 'firefox-nightly', - 'firefox-trunk', - ], - 'path': 'C:/Users/flotwig/AppData/Local/Firefox Nightly/firefox.exe', - 'version': '200', - 'findAppParams': { - 'appName': 'Firefox Nightly.app', - 'executable': 'Contents/MacOS/firefox', - 'bundleId': 'org.mozilla.nightly', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, -] - -exports['windows browser detection detects Chromium 64-bit install 1'] = [ - { - 'name': 'chromium', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chromium', - 'versionRegex': {}, - 'binary': [ - 'chromium-browser', - 'chromium', - ], - 'path': 'C:/Program Files/Google/chrome-win/chrome.exe', - 'version': '6.6.6', - 'findAppParams': { - 'appName': 'Chromium.app', - 'executable': 'Contents/MacOS/Chromium', - 'bundleId': 'org.chromium.Chromium', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, -] - -exports['windows browser detection detects Chromium 32-bit install in Chromium folder 1'] = [ - { - 'name': 'chromium', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chromium', - 'versionRegex': {}, - 'binary': [ - 'chromium-browser', - 'chromium', - ], - 'path': 'C:/Program Files (x86)/Google/Chromium/chrome.exe', - 'version': '7.7.7', - 'findAppParams': { - 'appName': 'Chromium.app', - 'executable': 'Contents/MacOS/Chromium', - 'bundleId': 'org.chromium.Chromium', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, -] - -exports['windows browser detection detects Chromium 64-bit install in Chromium folder 1'] = [ - { - 'name': 'chromium', - 'family': 'chromium', - 'channel': 'stable', - 'displayName': 'Chromium', - 'versionRegex': {}, - 'binary': [ - 'chromium-browser', - 'chromium', - ], - 'path': 'C:/Program Files/Google/Chromium/chrome.exe', - 'version': '8.8.8', - 'findAppParams': { - 'appName': 'Chromium.app', - 'executable': 'Contents/MacOS/Chromium', - 'bundleId': 'org.chromium.Chromium', - 'versionProperty': 'CFBundleShortVersionString', - }, - }, -] diff --git a/packages/launcher/lib/darwin/util.ts b/packages/launcher/lib/darwin/util.ts index 2e87bc4b709..da01b3d0a45 100644 --- a/packages/launcher/lib/darwin/util.ts +++ b/packages/launcher/lib/darwin/util.ts @@ -1,9 +1,9 @@ import Debug from 'debug' import { notInstalledErr } from '../errors' import { utils } from '../utils' -import * as fs from 'fs-extra' -import * as path from 'path' -import * as plist from 'plist' +import fs from 'fs-extra' +import path from 'path' +import plist from 'plist' const debugVerbose = Debug('cypress-verbose:launcher:darwin:util') diff --git a/packages/launcher/lib/windows/index.ts b/packages/launcher/lib/windows/index.ts index c1897b67420..e40dc37a0ce 100644 --- a/packages/launcher/lib/windows/index.ts +++ b/packages/launcher/lib/windows/index.ts @@ -1,4 +1,4 @@ -import * as fse from 'fs-extra' +import fs from 'fs-extra' import winVersionInfo from 'win-version-info' import os from 'os' import { join, normalize, win32 } from 'path' @@ -13,23 +13,23 @@ const debugVerbose = Debug('cypress-verbose:launcher:windows') function formFullAppPath (name: string) { return [ - `C:/Program Files (x86)/Google/Chrome/Application/${name}.exe`, `C:/Program Files/Google/Chrome/Application/${name}.exe`, + `C:/Program Files (x86)/Google/Chrome/Application/${name}.exe`, ].map(normalize) } function formChromeBetaAppPath () { return [ - 'C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe', 'C:/Program Files/Google/Chrome Beta/Application/chrome.exe', + 'C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe', ].map(normalize) } function formChromiumAppPath () { return [ - 'C:/Program Files (x86)/Google/chrome-win32/chrome.exe', 'C:/Program Files/Google/chrome-win/chrome.exe', 'C:/Program Files/Google/Chromium/chrome.exe', + 'C:/Program Files (x86)/Google/chrome-win32/chrome.exe', 'C:/Program Files (x86)/Google/Chromium/chrome.exe', ].map(normalize) } @@ -144,7 +144,7 @@ function getWindowsBrowser (browser: Browser): Promise { let path = doubleEscape(exePath) - return fse.pathExists(path) + return fs.pathExists(path) .then((exists) => { debugVerbose('found %s ? %o', path, { exists }) @@ -152,9 +152,7 @@ function getWindowsBrowser (browser: Browser): Promise { return tryNextExePath() } - // Use module.exports.getVersionString here, rather than our local reference - // to that variable so that the tests can easily mock it - return module.exports.getVersionString(path).then((version) => { + return getVersionString(path).then((version) => { debug('got version string for %s: %o', browser.name, { exePath, version }) return { diff --git a/packages/launcher/package.json b/packages/launcher/package.json index 40f45053fa6..1c4f334f1ce 100644 --- a/packages/launcher/package.json +++ b/packages/launcher/package.json @@ -11,7 +11,8 @@ "lint": "eslint --ext .js,.jsx,.ts,.tsx,.json, .", "size": "t=\"cypress-v0.0.0.tgz\"; yarn pack --filename \"${t}\"; wc -c \"cli/${t}\"; tar tvf \"${t}\"; rm \"${t}\";", "test": "yarn test-unit", - "test-unit": "mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json", + "test-debug": "vitest --inspect-brk --no-file-parallelism --test-timeout=0", + "test-unit": "vitest run", "tslint": "tslint --config ../ts/tslint.json --project ." }, "dependencies": { @@ -29,13 +30,9 @@ "@packages/data-context": "0.0.0-development", "@packages/ts": "0.0.0-development", "@packages/types": "0.0.0-development", - "chai": "3.5.0", - "chai-as-promised": "7.1.1", - "mocha": "3.5.3", "mock-fs": "5.4.0", - "sinon": "^10.0.0", - "sinon-chai": "3.7.0", - "typescript": "~5.4.5" + "typescript": "~5.4.5", + "vitest": "^3.2.4" }, "files": [ "index.js", diff --git a/packages/launcher/test/mocha.opts b/packages/launcher/test/mocha.opts deleted file mode 100644 index 3622a281707..00000000000 --- a/packages/launcher/test/mocha.opts +++ /dev/null @@ -1,4 +0,0 @@ -test/unit ---compilers ts:@packages/ts/register ---timeout 10000 ---recursive diff --git a/packages/launcher/test/spec_helper.ts b/packages/launcher/test/spec_helper.ts deleted file mode 100644 index 9c18fb9bd66..00000000000 --- a/packages/launcher/test/spec_helper.ts +++ /dev/null @@ -1,10 +0,0 @@ -import chai from 'chai' -import sinon from 'sinon' -import 'sinon-chai' -import chaiAsPromised from 'chai-as-promised' - -chai.use(chaiAsPromised) - -afterEach(() => { - sinon.restore() -}) diff --git a/packages/launcher/test/unit/__snapshots__/browsers.spec.ts.snap b/packages/launcher/test/unit/__snapshots__/browsers.spec.ts.snap new file mode 100644 index 00000000000..b4133413e0c --- /dev/null +++ b/packages/launcher/test/unit/__snapshots__/browsers.spec.ts.snap @@ -0,0 +1,131 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`browsers > returns the expected list of browsers 1`] = ` +[ + { + "binary": [ + "google-chrome", + "chrome", + "google-chrome-stable", + ], + "channel": "stable", + "displayName": "Chrome", + "family": "chromium", + "name": "chrome", + "validator": [Function], + "versionRegex": /Google Chrome\\(\\?! for Testing\\) \\(\\\\S\\+\\)/m, + }, + { + "binary": "google-chrome-beta", + "channel": "beta", + "displayName": "Chrome Beta", + "family": "chromium", + "name": "chrome", + "versionRegex": /Google Chrome \\(\\\\S\\+\\) beta/m, + }, + { + "binary": "google-chrome-canary", + "channel": "canary", + "displayName": "Chrome Canary", + "family": "chromium", + "name": "chrome", + "versionRegex": /Google Chrome Canary \\(\\\\S\\+\\)/m, + }, + { + "binary": "chrome", + "channel": "stable", + "displayName": "Chrome for Testing", + "family": "chromium", + "name": "chrome-for-testing", + "versionRegex": /Google Chrome for Testing \\(\\\\S\\+\\)/m, + }, + { + "binary": [ + "chromium-browser", + "chromium", + ], + "channel": "stable", + "displayName": "Chromium", + "family": "chromium", + "name": "chromium", + "versionRegex": /Chromium \\(\\\\S\\+\\)/m, + }, + { + "binary": "firefox", + "channel": "stable", + "displayName": "Firefox", + "family": "firefox", + "name": "firefox", + "validator": [Function], + "versionRegex": /\\^Mozilla Firefox \\(\\[\\^\\\\sab\\]\\+\\)\\$/m, + }, + { + "binary": [ + "firefox-developer-edition", + "firefox", + ], + "channel": "dev", + "displayName": "Firefox Developer Edition", + "family": "firefox", + "name": "firefox", + "validator": [Function], + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+b\\\\S\\*\\)\\$/m, + }, + { + "binary": [ + "firefox-nightly", + "firefox-trunk", + ], + "channel": "nightly", + "displayName": "Firefox Nightly", + "family": "firefox", + "name": "firefox", + "validator": [Function], + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+a\\\\S\\*\\)\\$/m, + }, + { + "binary": [ + "edge", + "microsoft-edge", + ], + "channel": "stable", + "displayName": "Edge", + "family": "chromium", + "name": "edge", + "versionRegex": /Microsoft Edge \\(\\\\S\\+\\)/im, + }, + { + "binary": [ + "edge-beta", + "microsoft-edge-beta", + ], + "channel": "beta", + "displayName": "Edge Beta", + "family": "chromium", + "name": "edge", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= beta\\)\\|\\(\\?<=beta \\)\\\\S\\*\\)/im, + }, + { + "binary": [ + "edge-canary", + "microsoft-edge-canary", + ], + "channel": "canary", + "displayName": "Edge Canary", + "family": "chromium", + "name": "edge", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= canary\\)\\|\\(\\?<=canary \\)\\\\S\\*\\)/im, + }, + { + "binary": [ + "edge-dev", + "microsoft-edge-dev", + ], + "channel": "dev", + "displayName": "Edge Dev", + "family": "chromium", + "name": "edge", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= dev\\)\\|\\(\\?<=dev \\)\\\\S\\*\\)/im, + }, +] +`; diff --git a/packages/launcher/test/unit/__snapshots__/darwin.spec.ts.snap b/packages/launcher/test/unit/__snapshots__/darwin.spec.ts.snap new file mode 100644 index 00000000000..c8039cb57e6 --- /dev/null +++ b/packages/launcher/test/unit/__snapshots__/darwin.spec.ts.snap @@ -0,0 +1,227 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`darwin browser detection > detects browsers as expected 1`] = ` +[ + { + "binary": [ + "google-chrome", + "chrome", + "google-chrome-stable", + ], + "channel": "stable", + "displayName": "Chrome", + "family": "chromium", + "findAppParams": { + "appName": "Google Chrome.app", + "bundleId": "com.google.Chrome", + "executable": "Contents/MacOS/Google Chrome", + "versionProperty": "KSVersion", + }, + "name": "chrome", + "path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + "validator": [Function], + "version": "someVersion", + "versionRegex": /Google Chrome\\(\\?! for Testing\\) \\(\\\\S\\+\\)/m, + }, + { + "binary": "google-chrome-beta", + "channel": "beta", + "displayName": "Chrome Beta", + "family": "chromium", + "findAppParams": { + "appName": "Google Chrome Beta.app", + "bundleId": "com.google.Chrome.beta", + "executable": "Contents/MacOS/Google Chrome Beta", + "versionProperty": "KSVersion", + }, + "name": "chrome", + "path": "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta", + "version": "someVersion", + "versionRegex": /Google Chrome \\(\\\\S\\+\\) beta/m, + }, + { + "binary": "google-chrome-canary", + "channel": "canary", + "displayName": "Chrome Canary", + "family": "chromium", + "findAppParams": { + "appName": "Google Chrome Canary.app", + "bundleId": "com.google.Chrome.canary", + "executable": "Contents/MacOS/Google Chrome Canary", + "versionProperty": "KSVersion", + }, + "name": "chrome", + "path": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary", + "version": "someVersion", + "versionRegex": /Google Chrome Canary \\(\\\\S\\+\\)/m, + }, + { + "binary": "chrome", + "channel": "stable", + "displayName": "Chrome for Testing", + "family": "chromium", + "findAppParams": { + "appName": "Google Chrome for Testing.app", + "bundleId": "com.google.chrome.for.testing", + "executable": "Contents/MacOS/Google Chrome for Testing", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "chrome-for-testing", + "path": "/Applications/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing", + "version": "someVersion", + "versionRegex": /Google Chrome for Testing \\(\\\\S\\+\\)/m, + }, + { + "binary": [ + "chromium-browser", + "chromium", + ], + "channel": "stable", + "displayName": "Chromium", + "family": "chromium", + "findAppParams": { + "appName": "Chromium.app", + "bundleId": "org.chromium.Chromium", + "executable": "Contents/MacOS/Chromium", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "chromium", + "path": "/Applications/Chromium.app/Contents/MacOS/Chromium", + "version": "someVersion", + "versionRegex": /Chromium \\(\\\\S\\+\\)/m, + }, + { + "binary": "firefox", + "channel": "stable", + "displayName": "Firefox", + "family": "firefox", + "findAppParams": { + "appName": "Firefox.app", + "bundleId": "org.mozilla.firefox", + "executable": "Contents/MacOS/firefox", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "firefox", + "path": "/Applications/Firefox.app/Contents/MacOS/firefox", + "validator": [Function], + "version": "someVersion", + "versionRegex": /\\^Mozilla Firefox \\(\\[\\^\\\\sab\\]\\+\\)\\$/m, + }, + { + "binary": [ + "firefox-developer-edition", + "firefox", + ], + "channel": "dev", + "displayName": "Firefox Developer Edition", + "family": "firefox", + "findAppParams": { + "appName": "Firefox Developer Edition.app", + "bundleId": "org.mozilla.firefoxdeveloperedition", + "executable": "Contents/MacOS/firefox", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "firefox", + "path": "/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox", + "validator": [Function], + "version": "someVersion", + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+b\\\\S\\*\\)\\$/m, + }, + { + "binary": [ + "firefox-nightly", + "firefox-trunk", + ], + "channel": "nightly", + "displayName": "Firefox Nightly", + "family": "firefox", + "findAppParams": { + "appName": "Firefox Nightly.app", + "bundleId": "org.mozilla.nightly", + "executable": "Contents/MacOS/firefox", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "firefox", + "path": "/Applications/Firefox Nightly.app/Contents/MacOS/firefox", + "validator": [Function], + "version": "someVersion", + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+a\\\\S\\*\\)\\$/m, + }, + { + "binary": [ + "edge", + "microsoft-edge", + ], + "channel": "stable", + "displayName": "Edge", + "family": "chromium", + "findAppParams": { + "appName": "Microsoft Edge.app", + "bundleId": "com.microsoft.Edge", + "executable": "Contents/MacOS/Microsoft Edge", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "edge", + "path": "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", + "version": "someVersion", + "versionRegex": /Microsoft Edge \\(\\\\S\\+\\)/im, + }, + { + "binary": [ + "edge-beta", + "microsoft-edge-beta", + ], + "channel": "beta", + "displayName": "Edge Beta", + "family": "chromium", + "findAppParams": { + "appName": "Microsoft Edge Beta.app", + "bundleId": "com.microsoft.Edge.Beta", + "executable": "Contents/MacOS/Microsoft Edge Beta", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "edge", + "path": "/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta", + "version": "someVersion", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= beta\\)\\|\\(\\?<=beta \\)\\\\S\\*\\)/im, + }, + { + "binary": [ + "edge-canary", + "microsoft-edge-canary", + ], + "channel": "canary", + "displayName": "Edge Canary", + "family": "chromium", + "findAppParams": { + "appName": "Microsoft Edge Canary.app", + "bundleId": "com.microsoft.Edge.Canary", + "executable": "Contents/MacOS/Microsoft Edge Canary", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "edge", + "path": "/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary", + "version": "someVersion", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= canary\\)\\|\\(\\?<=canary \\)\\\\S\\*\\)/im, + }, + { + "binary": [ + "edge-dev", + "microsoft-edge-dev", + ], + "channel": "dev", + "displayName": "Edge Dev", + "family": "chromium", + "findAppParams": { + "appName": "Microsoft Edge Dev.app", + "bundleId": "com.microsoft.Edge.Dev", + "executable": "Contents/MacOS/Microsoft Edge Dev", + "versionProperty": "CFBundleShortVersionString", + }, + "name": "edge", + "path": "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev", + "version": "someVersion", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= dev\\)\\|\\(\\?<=dev \\)\\\\S\\*\\)/im, + }, +] +`; diff --git a/packages/launcher/test/unit/__snapshots__/windows.spec.ts.snap b/packages/launcher/test/unit/__snapshots__/windows.spec.ts.snap new file mode 100644 index 00000000000..e5962ff17c8 --- /dev/null +++ b/packages/launcher/test/unit/__snapshots__/windows.spec.ts.snap @@ -0,0 +1,291 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`windows browser detection > detects Chrome 64-bit install 1`] = ` +{ + "binary": [ + "google-chrome", + "chrome", + "google-chrome-stable", + ], + "channel": "stable", + "displayName": "Chrome", + "family": "chromium", + "name": "chrome", + "path": "C:/Program Files/Google/Chrome/Application/chrome.exe", + "validator": [Function], + "version": "4.4.4", + "versionRegex": /Google Chrome\\(\\?! for Testing\\) \\(\\\\S\\+\\)/m, +} +`; + +exports[`windows browser detection > detects Chrome Beta 64-bit install 1`] = ` +{ + "binary": "google-chrome-beta", + "channel": "beta", + "displayName": "Chrome Beta", + "family": "chromium", + "name": "chrome", + "path": "C:/Program Files/Google/Chrome Beta/Application/chrome.exe", + "version": "9.0.1", + "versionRegex": /Google Chrome \\(\\\\S\\+\\) beta/m, +} +`; + +exports[`windows browser detection > detects Chrome for Testing 32-bit install 1`] = ` +{ + "binary": "chrome", + "channel": "stable", + "displayName": "Chrome for Testing", + "family": "chromium", + "name": "chrome-for-testing", + "path": "C:/Program Files (x86)/Google/Chrome for Testing/chrome.exe", + "version": "5.5.5", + "versionRegex": /Google Chrome for Testing \\(\\\\S\\+\\)/m, +} +`; + +exports[`windows browser detection > detects Chromium 32-bit install in Chromium folder 1`] = ` +{ + "binary": [ + "chromium-browser", + "chromium", + ], + "channel": "stable", + "displayName": "Chromium", + "family": "chromium", + "name": "chromium", + "path": "C:/Program Files (x86)/Google/Chromium/chrome.exe", + "version": "7.7.7", + "versionRegex": /Chromium \\(\\\\S\\+\\)/m, +} +`; + +exports[`windows browser detection > detects Chromium 64-bit install 1`] = ` +{ + "binary": [ + "chromium-browser", + "chromium", + ], + "channel": "stable", + "displayName": "Chromium", + "family": "chromium", + "name": "chromium", + "path": "C:/Program Files/Google/chrome-win/chrome.exe", + "version": "6.6.6", + "versionRegex": /Chromium \\(\\\\S\\+\\)/m, +} +`; + +exports[`windows browser detection > detects Chromium 64-bit install in Chromium folder 1`] = ` +{ + "binary": [ + "chromium-browser", + "chromium", + ], + "channel": "stable", + "displayName": "Chromium", + "family": "chromium", + "name": "chromium", + "path": "C:/Program Files/Google/Chromium/chrome.exe", + "version": "8.8.8", + "versionRegex": /Chromium \\(\\\\S\\+\\)/m, +} +`; + +exports[`windows browser detection > detects Firefox local installs 1`] = ` +[ + { + "binary": "firefox", + "channel": "stable", + "displayName": "Firefox", + "family": "firefox", + "name": "firefox", + "path": "C:/Users/flotwig/AppData/Local/Mozilla Firefox/firefox.exe", + "validator": [Function], + "version": "100", + "versionRegex": /\\^Mozilla Firefox \\(\\[\\^\\\\sab\\]\\+\\)\\$/m, + }, + { + "binary": [ + "firefox-developer-edition", + "firefox", + ], + "channel": "dev", + "displayName": "Firefox Developer Edition", + "family": "firefox", + "name": "firefox", + "path": "C:/Users/flotwig/AppData/Local/Firefox Developer Edition/firefox.exe", + "validator": [Function], + "version": "300", + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+b\\\\S\\*\\)\\$/m, + }, + { + "binary": [ + "firefox-nightly", + "firefox-trunk", + ], + "channel": "nightly", + "displayName": "Firefox Nightly", + "family": "firefox", + "name": "firefox", + "path": "C:/Users/flotwig/AppData/Local/Firefox Nightly/firefox.exe", + "validator": [Function], + "version": "200", + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+a\\\\S\\*\\)\\$/m, + }, +] +`; + +exports[`windows browser detection > detects browsers as expected 1`] = ` +[ + { + "binary": [ + "google-chrome", + "chrome", + "google-chrome-stable", + ], + "channel": "stable", + "displayName": "Chrome", + "family": "chromium", + "name": "chrome", + "path": "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe", + "validator": [Function], + "version": "1.2.3", + "versionRegex": /Google Chrome\\(\\?! for Testing\\) \\(\\\\S\\+\\)/m, + }, + { + "binary": "google-chrome-beta", + "channel": "beta", + "displayName": "Chrome Beta", + "family": "chromium", + "name": "chrome", + "path": "C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe", + "version": "6.7.8", + "versionRegex": /Google Chrome \\(\\\\S\\+\\) beta/m, + }, + { + "binary": "google-chrome-canary", + "channel": "canary", + "displayName": "Chrome Canary", + "family": "chromium", + "name": "chrome", + "path": "C:/Users/flotwig/AppData/Local/Google/Chrome SxS/Application/chrome.exe", + "version": "3.4.5", + "versionRegex": /Google Chrome Canary \\(\\\\S\\+\\)/m, + }, + { + "binary": "chrome", + "channel": "stable", + "displayName": "Chrome for Testing", + "family": "chromium", + "name": "chrome-for-testing", + "path": "C:/Program Files/Google/Chrome for Testing/chrome.exe", + "version": "1.2.3", + "versionRegex": /Google Chrome for Testing \\(\\\\S\\+\\)/m, + }, + { + "binary": [ + "chromium-browser", + "chromium", + ], + "channel": "stable", + "displayName": "Chromium", + "family": "chromium", + "name": "chromium", + "path": "C:/Program Files/Google/chrome-win/chrome.exe", + "version": "2.3.4", + "versionRegex": /Chromium \\(\\\\S\\+\\)/m, + }, + { + "binary": "firefox", + "channel": "stable", + "displayName": "Firefox", + "family": "firefox", + "name": "firefox", + "path": "C:/Program Files/Mozilla Firefox/firefox.exe", + "validator": [Function], + "version": "72", + "versionRegex": /\\^Mozilla Firefox \\(\\[\\^\\\\sab\\]\\+\\)\\$/m, + }, + { + "binary": [ + "firefox-developer-edition", + "firefox", + ], + "channel": "dev", + "displayName": "Firefox Developer Edition", + "family": "firefox", + "name": "firefox", + "path": "C:/Program Files (x86)/Firefox Developer Edition/firefox.exe", + "validator": [Function], + "version": "73", + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+b\\\\S\\*\\)\\$/m, + }, + { + "binary": [ + "firefox-nightly", + "firefox-trunk", + ], + "channel": "nightly", + "displayName": "Firefox Nightly", + "family": "firefox", + "name": "firefox", + "path": "C:/Program Files/Firefox Nightly/firefox.exe", + "validator": [Function], + "version": "74", + "versionRegex": /\\^Mozilla Firefox \\(\\\\S\\+a\\\\S\\*\\)\\$/m, + }, + { + "binary": [ + "edge", + "microsoft-edge", + ], + "channel": "stable", + "displayName": "Edge", + "family": "chromium", + "name": "edge", + "path": "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe", + "version": "11", + "versionRegex": /Microsoft Edge \\(\\\\S\\+\\)/im, + }, + { + "binary": [ + "edge-beta", + "microsoft-edge-beta", + ], + "channel": "beta", + "displayName": "Edge Beta", + "family": "chromium", + "name": "edge", + "path": "C:/Program Files (x86)/Microsoft/Edge Beta/Application/msedge.exe", + "version": "12", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= beta\\)\\|\\(\\?<=beta \\)\\\\S\\*\\)/im, + }, + { + "binary": [ + "edge-canary", + "microsoft-edge-canary", + ], + "channel": "canary", + "displayName": "Edge Canary", + "family": "chromium", + "name": "edge", + "path": "C:/Users/flotwig/AppData/Local/Microsoft/Edge SxS/Application/msedge.exe", + "version": "14", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= canary\\)\\|\\(\\?<=canary \\)\\\\S\\*\\)/im, + }, + { + "binary": [ + "edge-dev", + "microsoft-edge-dev", + ], + "channel": "dev", + "displayName": "Edge Dev", + "family": "chromium", + "name": "edge", + "path": "C:/Program Files (x86)/Microsoft/Edge Dev/Application/msedge.exe", + "version": "13", + "versionRegex": /Microsoft Edge\\.\\+\\?\\(\\\\S\\*\\(\\?= dev\\)\\|\\(\\?<=dev \\)\\\\S\\*\\)/im, + }, +] +`; diff --git a/packages/launcher/test/unit/browsers_spec.ts b/packages/launcher/test/unit/browsers.spec.ts similarity index 80% rename from packages/launcher/test/unit/browsers_spec.ts rename to packages/launcher/test/unit/browsers.spec.ts index 19f8f9ba808..edfdb2ad1ca 100644 --- a/packages/launcher/test/unit/browsers_spec.ts +++ b/packages/launcher/test/unit/browsers.spec.ts @@ -1,18 +1,17 @@ +import { describe, it, expect } from 'vitest' import _ from 'lodash' import { knownBrowsers } from '../../lib/known-browsers' -import { expect } from 'chai' -const snapshot = require('snap-shot-it') describe('browsers', () => { it('returns the expected list of browsers', () => { - snapshot(knownBrowsers) + expect(knownBrowsers).toMatchSnapshot() }) // https://github.com/cypress-io/cypress/issues/6669 it('exports multiline versionRegexes', () => { expect(_.every(knownBrowsers.map(({ versionRegex }) => { return versionRegex.multiline - }))).to.be.true + }))).toBe(true) }) describe('browser.validator', () => { @@ -21,7 +20,7 @@ describe('browsers', () => { path: '/path/to/firefox', } - context('validator defined', () => { + describe('validator defined', () => { it('when conditions met: marks browser as not supported and generates warning message', () => { const foundBrowser = { ...firefoxBrowser, @@ -43,8 +42,8 @@ describe('browsers', () => { const result = foundBrowser.validator(foundBrowser, 'win32') - expect(result.isSupported).to.be.false - expect(result.warningMessage).to.contain('Cypress does not support running Firefox version 101 on Windows due to a blocking bug in Firefox.') + expect(result.isSupported).toBe(false) + expect(result.warningMessage).toContain('Cypress does not support running Firefox version 101 on Windows due to a blocking bug in Firefox.') }) it('when conditions not met: marks browser as not supported and generates warning message', () => { @@ -68,8 +67,8 @@ describe('browsers', () => { const result = foundBrowser.validator(foundBrowser, 'win32') - expect(result.isSupported).to.be.true - expect(result.warningMessage).to.be.undefined + expect(result.isSupported).toBe(true) + expect(result.warningMessage).toBeUndefined() }) describe('firefox validation', () => { @@ -85,8 +84,8 @@ describe('browsers', () => { displayName: 'Firefox', }) - expect(result.isSupported).to.be.false - expect(result.warningMessage).to.equal('Cypress does not support running Firefox version 134 due to lack of WebDriver BiDi support. To use Firefox with Cypress, install version 135 or newer.') + expect(result.isSupported).toBe(false) + expect(result.warningMessage).toEqual('Cypress does not support running Firefox version 134 due to lack of WebDriver BiDi support. To use Firefox with Cypress, install version 135 or newer.') }) }) }) diff --git a/packages/launcher/test/unit/darwin.spec.ts b/packages/launcher/test/unit/darwin.spec.ts new file mode 100644 index 00000000000..71d1467cd60 --- /dev/null +++ b/packages/launcher/test/unit/darwin.spec.ts @@ -0,0 +1,208 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest' +import os from 'os' +import cp from 'child_process' +import fs from 'fs-extra' +import { PassThrough } from 'stream' +import { FoundBrowser } from '@packages/types' +import * as darwinHelper from '../../lib/darwin' +import * as linuxHelper from '../../lib/linux' +import * as darwinUtil from '../../lib/darwin/util' +import { launch } from '../../lib/browsers' +import { knownBrowsers } from '../../lib/known-browsers' + +vi.mock('os', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + arch: vi.fn(), + platform: vi.fn(), + }, + } +}) + +vi.mock('fs-extra', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + readFile: vi.fn(), + }, + } +}) + +vi.mock('child_process', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + spawn: vi.fn(), + }, + } +}) + +function generatePlist (key, value) { + return ` + + + + + ${key} + ${value} + + + ` +} + +describe('darwin browser detection', () => { + beforeEach(() => { + vi.unstubAllEnvs() + vi.resetAllMocks() + vi.mocked(fs.readFile).mockRejectedValue({ code: 'ENOENT' }) + }) + + it('detects browsers as expected', async () => { + // this test uses the macOS detectors to stub out the expected calls + const flatFindAppParams: darwinUtil.FindAppParams[] = [] + + for (const browser in darwinHelper.browsers) { + for (const channel in darwinHelper.browsers[browser]) { + flatFindAppParams.push(darwinHelper.browsers[browser][channel]) + } + } + + // @ts-expect-error + vi.mocked(fs.readFile).mockImplementation((file: string, _options: any): Promise => { + const foundAppParams = flatFindAppParams.find((findAppParams) => `/Applications/${findAppParams.appName}/Contents/Info.plist` === file) + + if (foundAppParams) { + return Promise.resolve(generatePlist(foundAppParams.versionProperty, 'someVersion')) + } + + throw new Error('File not found') + }) + + const mappedBrowsers = [] + + for (const browser of knownBrowsers) { + const foundBrowser = await darwinHelper.detect(browser) + const findAppParams = darwinHelper.browsers[browser.name][browser.channel] + + mappedBrowsers.push({ + ...browser, + ...foundBrowser, + findAppParams, + }) + } + + expect(mappedBrowsers).toMatchSnapshot() + }) + + it('getVersionString is re-exported from linuxHelper', () => { + expect(darwinHelper.getVersionString).toEqual(linuxHelper.getVersionString) + }) + + describe('forces correct architecture', () => { + beforeEach(() => { + vi.unstubAllEnvs() + vi.stubEnv('env2', 'false') + vi.stubEnv('env3', 'true') + vi.mocked(os.platform).mockReturnValue('darwin') + vi.mocked(cp.spawn).mockImplementation(() => { + const mock: any = { + on: vi.fn(), + once: vi.fn(), + stdout: new PassThrough(), + stderr: new PassThrough(), + kill: vi.fn(), + } + + mock.on.mockImplementation((event: string, callback: (...args: any[]) => void) => { + if (event === 'exit') { + setTimeout(() => callback(), 0) + } + + if (event === 'close') { + setTimeout(() => callback(), 0) + } + }) + + mock.stderr.end() + mock.stdout.end() + + return mock as cp.ChildProcess + }) + }) + + describe('in version detection', () => { + it('uses arch and ARCHPREFERENCE on arm64', async () => { + vi.mocked(os.arch).mockReturnValue('arm64') + + // this will error since we aren't setting stdout + await (darwinHelper.detect(knownBrowsers[0]).catch(() => {})) + + expect(cp.spawn).toHaveBeenNthCalledWith(1, 'arch', [knownBrowsers[0].binary, '--version'], expect.objectContaining({ + env: expect.objectContaining({ + ARCHPREFERENCE: 'arm64,x86_64', + env2: 'false', + env3: 'true', + }), + })) + }) + + it('does not use `arch` on x64', async () => { + vi.mocked(os.arch).mockReturnValue('x64') + + // this will error since we aren't setting stdout + await (darwinHelper.detect(knownBrowsers[0]).catch(() => {})) + + expect(cp.spawn).toHaveBeenNthCalledWith(1, knownBrowsers[0].binary, ['--version'], expect.objectContaining({ + env: expect.objectContaining({ + env2: 'false', + env3: 'true', + }), + })) + }) + }) + + describe('in browser launching', () => { + it('uses arch and ARCHPREFERENCE on arm64', async () => { + vi.mocked(os.arch).mockReturnValue('arm64') + + await launch({ path: 'chrome' } as unknown as FoundBrowser, 'url', 123, ['arg1'], { env1: 'true', env2: 'true' }) + + expect(cp.spawn).toHaveBeenNthCalledWith(1, 'arch', ['chrome', 'url', 'arg1'], expect.objectContaining({ + env: expect.objectContaining({ + ARCHPREFERENCE: 'arm64,x86_64', + env1: 'true', + env2: 'false', + env3: 'true', + }), + })) + }) + + it('does not use `arch` on x64', async () => { + vi.mocked(os.arch).mockReturnValue('x64') + + await launch({ path: 'chrome' } as unknown as FoundBrowser, 'url', 123, ['arg1'], { env1: 'true', env2: 'true' }) + + expect(cp.spawn).toHaveBeenNthCalledWith(1, 'chrome', ['url', 'arg1'], expect.objectContaining({ + env: expect.objectContaining({ + env1: 'true', + env2: 'false', + env3: 'true', + }), + })) + + // @ts-expect-error + expect(cp.spawn.mock.calls[0][2].env).not.toHaveProperty('ARCHPREFERENCE') + }) + }) + }) +}) diff --git a/packages/launcher/test/unit/darwin_spec.ts b/packages/launcher/test/unit/darwin_spec.ts deleted file mode 100644 index 0e03b11904a..00000000000 --- a/packages/launcher/test/unit/darwin_spec.ts +++ /dev/null @@ -1,175 +0,0 @@ -import _ from 'lodash' -import os from 'os' -import cp from 'child_process' -import * as darwinHelper from '../../lib/darwin' -import * as linuxHelper from '../../lib/linux' -import * as darwinUtil from '../../lib/darwin/util' -import { utils } from '../../lib/utils' -import { expect } from 'chai' -import sinon, { SinonStub } from 'sinon' -import { launch } from '../../lib/browsers' -import { knownBrowsers } from '../../lib/known-browsers' -import Bluebird from 'bluebird' -import fse from 'fs-extra' -import snapshot from 'snap-shot-it' -import { PassThrough } from 'stream' -import { FoundBrowser } from '@packages/types' - -function generatePlist (key, value) { - return ` - - - - - ${key} - ${value} - - - ` -} - -function stubBrowser (findAppParams: darwinUtil.FindAppParams) { - (utils.getOutput as unknown as SinonStub) - .withArgs(`mdfind 'kMDItemCFBundleIdentifier=="${findAppParams.bundleId}"' | head -1`) - .resolves({ stdout: `/Applications/${findAppParams.appName}` }) - - ;(fse.readFile as SinonStub) - .withArgs(`/Applications/${findAppParams.appName}/Contents/Info.plist`) - .resolves(generatePlist(findAppParams.versionProperty, 'someVersion')) -} - -function spawnStub () { - const stub: any = { - on: sinon.stub(), - stdout: new PassThrough(), - stderr: new PassThrough(), - kill: sinon.stub(), - } - - stub.once = stub.on - - stub.on.withArgs('exit').callsArgAsync(1) - stub.on.withArgs('close').callsArgAsync(1) - - stub.stderr.end() - stub.stdout.end() - - return stub as cp.ChildProcess -} - -describe('darwin browser detection', () => { - let getOutput: SinonStub - - beforeEach(() => { - sinon.stub(fse, 'readFile').rejects({ code: 'ENOENT' }) - getOutput = sinon.stub(utils, 'getOutput').resolves({ stdout: '' }) - }) - - it('detects browsers as expected', async () => { - // this test uses the macOS detectors to stub out the expected calls - _.forEach(darwinHelper.browsers, (channels) => { - _.forEach(channels, stubBrowser) - }) - - // then, it uses the main browsers list to attempt detection of all browsers, which should succeed - const detected = (await Bluebird.mapSeries(knownBrowsers, (browser) => { - return darwinHelper.detect(browser) - .then((foundBrowser) => { - const findAppParams = darwinHelper.browsers[browser.name][browser.channel] - - return _.merge(browser, foundBrowser, { findAppParams }) - }) - })) - - snapshot(detected) - }) - - it('getVersionString is re-exported from linuxHelper', () => { - expect(darwinHelper.getVersionString).to.eq(linuxHelper.getVersionString) - }) - - context('forces correct architecture', () => { - function stubForArch (arch: 'arm64' | 'x64') { - sinon.stub(process, 'env').value({ env2: 'false', env3: 'true' }) - sinon.stub(os, 'arch').returns(arch) - sinon.stub(os, 'platform').returns('darwin') - getOutput.restore() - - return sinon.stub(cp, 'spawn').returns(spawnStub()) - } - - context('in version detection', () => { - it('uses arch and ARCHPREFERENCE on arm64', async () => { - const cpSpawn = stubForArch('arm64') - - // this will error since we aren't setting stdout - await (darwinHelper.detect(knownBrowsers[0]).catch(() => {})) - - // first call is mdfind, second call is getVersionString - const { args } = cpSpawn.getCall(1) - - expect(args[0]).to.eq('arch') - expect(args[1]).to.deep.eq([knownBrowsers[0].binary, '--version']) - expect(args[2].env).to.deep.include({ - ARCHPREFERENCE: 'arm64,x86_64', - env2: 'false', - env3: 'true', - }) - }) - - it('does not use `arch` on x64', async () => { - const cpSpawn = stubForArch('x64') - - // this will error since we aren't setting stdout - await (darwinHelper.detect(knownBrowsers[0]).catch(() => {})) - - // first call is mdfind, second call is getVersionString - const { args } = cpSpawn.getCall(1) - - expect(args[0]).to.eq(knownBrowsers[0].binary) - expect(args[1]).to.deep.eq(['--version']) - expect(args[2].env).to.deep.include({ - env2: 'false', - env3: 'true', - }) - }) - }) - - context('in browser launching', () => { - it('uses arch and ARCHPREFERENCE on arm64', async () => { - const cpSpawn = stubForArch('arm64') - - await launch({ path: 'chrome' } as unknown as FoundBrowser, 'url', 123, ['arg1'], { env1: 'true', env2: 'true' }) - - const { args } = cpSpawn.getCall(0) - - expect(args[0]).to.eq('arch') - expect(args[1]).to.deep.eq(['chrome', 'url', 'arg1']) - expect(args[2].env).to.deep.include({ - ARCHPREFERENCE: 'arm64,x86_64', - env1: 'true', - env2: 'false', - env3: 'true', - }) - }) - - it('does not use `arch` on x64', async () => { - const cpSpawn = stubForArch('x64') - - await launch({ path: 'chrome' } as unknown as FoundBrowser, 'url', 123, ['arg1'], { env1: 'true', env2: 'true' }) - - const { args } = cpSpawn.getCall(0) - - expect(args[0]).to.eq('chrome') - expect(args[1]).to.deep.eq(['url', 'arg1']) - expect(args[2].env).to.deep.include({ - env1: 'true', - env2: 'false', - env3: 'true', - }) - - expect(args[2].env).to.not.have.property('ARCHPREFERENCE') - }) - }) - }) -}) diff --git a/packages/launcher/test/unit/detect.spec.ts b/packages/launcher/test/unit/detect.spec.ts new file mode 100644 index 00000000000..8ef8f44714c --- /dev/null +++ b/packages/launcher/test/unit/detect.spec.ts @@ -0,0 +1,287 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest' +import _ from 'lodash' +import cp from 'child_process' +import { EventEmitter } from 'stream' +import { detect, detectByPath, getMajorVersion } from '../../lib/detect' +import { goalBrowsers } from '../fixtures' +import os from 'os' +import { log } from '../log' +import { detect as linuxDetect } from '../../lib/linux' +import { detect as darwinDetect } from '../../lib/darwin' +import { detect as windowsDetect } from '../../lib/windows' +import type { Browser } from '@packages/types' + +vi.mock('child_process', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + spawn: vi.fn(), + }, + } +}) + +vi.mock('../../lib/linux', async (importActual) => { + const actual = await importActual() + + return { + // @ts-expect-error + ...actual, + detect: vi.fn(), + } +}) + +vi.mock('../../lib/darwin', async (importActual) => { + const actual = await importActual() + + return { + // @ts-expect-error + ...actual, + detect: vi.fn(), + } +}) + +vi.mock('../../lib/windows', async (importActual) => { + const actual = await importActual() + + return { + // @ts-expect-error + ...actual, + detect: vi.fn(), + } +}) + +const isWindows = () => { + return os.platform() === 'win32' +} + +describe('detect', () => { + beforeEach(async () => { + vi.unstubAllEnvs() + vi.resetAllMocks() + + const { detect: linuxDetectActual } = await vi.importActual('../../lib/linux') + const { detect: darwinDetectActual } = await vi.importActual('../../lib/darwin') + const { detect: windowsDetectActual } = await vi.importActual('../../lib/windows') + + vi.mocked(linuxDetect).mockImplementation(linuxDetectActual) + vi.mocked(darwinDetect).mockImplementation(darwinDetectActual) + vi.mocked(windowsDetect).mockImplementation(windowsDetectActual) + + const { spawn } = await vi.importActual('child_process') + + vi.mocked(cp.spawn).mockImplementation(spawn) + }) + + // making simple to debug tests + // using DEBUG=... flag + + // we are only going to run tests on platforms with at least + // one browser. This test, is really E2E because it finds + // real browsers + it('detects available browsers', async () => { + const browsers = await detect() + + log('detected browsers %j', browsers) + expect(browsers).toBeInstanceOf(Array) + + const mainProps = browsers.map((val) => _.pick(val, ['name', 'version'])) + + log('%d browsers\n%j', browsers.length, mainProps) + + if (isWindows()) { + // we might not find any browsers on Windows CI + expect(browsers.length).toBeGreaterThanOrEqual(0) + } else { + expect(browsers.length).toBeGreaterThan(0) + } + }) + + describe('#getMajorVersion', () => { + it('parses major version from provided string', () => { + expect(getMajorVersion('123.45.67')).toEqual('123') + expect(getMajorVersion('Browser 77.1.0')).toEqual('Browser 77') + expect(getMajorVersion('999')).toEqual('999') + }) + }) + + describe('#detect', () => { + const testBrowser = { + name: 'test-browser', + family: 'chromium', + channel: 'test-channel', + displayName: 'Test Browser', + versionRegex: /Test Browser (\S+)/m, + binary: 'test-browser-beta', + } + + it('validates browser with own validator property', async () => { + // @ts-expect-error + vi.mocked(linuxDetect).mockImplementation((browser) => { + return Promise.resolve({ + name: browser.name, + path: '/path/to/test-browser', + version: '130', + }) + }) + + vi.mocked(darwinDetect).mockImplementation((browser) => { + return Promise.resolve({ + name: browser.name, + path: '/path/to/test-browser', + version: '130', + }) + }) + + // @ts-expect-error + vi.mocked(windowsDetect).mockImplementation((browser) => { + return Promise.resolve({ + name: browser.name, + path: '/path/to/test-browser', + version: '130', + }) + }) + + const mockValidator = vi.fn().mockReturnValue({ isSupported: true }) + + const foundBrowsers = await detect([{ ...testBrowser as Browser, validator: mockValidator }]) + + expect(foundBrowsers).toHaveLength(1) + + const foundTestBrowser = foundBrowsers[0] + + expect(foundTestBrowser.name).toEqual('test-browser') + expect(foundTestBrowser.displayName).toEqual('Test Browser') + expect(foundTestBrowser.majorVersion, 'majorVersion').toEqual('130') + expect(foundTestBrowser.unsupportedVersion, 'unsupportedVersion').toBeUndefined() + expect(foundTestBrowser.warning, 'warning').toBeUndefined() + expect(mockValidator).toHaveBeenCalled() + }) + }) + + describe('#detectByPath', () => { + let cpSpawnCallback: (cmd: string, args: readonly string[], opts, cp: cp.ChildProcess) => void + + beforeEach(() => { + vi.unstubAllEnvs() + vi.resetAllMocks() + + vi.mocked(cp.spawn).mockImplementation((cmd, args, opts) => { + const cpSpawnMock = { + on: vi.fn(), + stdout: new EventEmitter(), + stderr: new EventEmitter(), + kill: vi.fn(), + } + + cpSpawnMock.on.mockImplementation((event: string, callback: (...args: any[]) => void) => { + if (event === 'exit') { + setTimeout(() => callback(), 0) + } + + if (event === 'close') { + setTimeout(() => callback(), 0) + } + }) + + cpSpawnCallback(cmd, args, opts, cpSpawnMock as unknown as cp.ChildProcess) + + return cpSpawnMock as unknown as cp.ChildProcess + }) + + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + // FIXME: these tests really should be reworked to run the same regardless of OS/CPU architecture + const command = os.arch() === 'arm64' ? args[0] : cmd + + if (command === '/Applications/My Shiny New Browser.app') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'foo-browser v100.1.2.3') + }, 0) + + return + } + + if (command === '/foo/bar/browser') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'foo-browser v9001.1.2.3') + }, 0) + + return + } + + if (command === '/not/a/browser') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'not a browser version string') + }, 0) + + return + } + + if (command === '/not/a/real/path') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', '') + }, 0) + + return + } + } + }) + + it('detects by path', async () => { + // @ts-expect-error + const foundBrowser = await detectByPath('/foo/bar/browser', goalBrowsers) + + const expectedBrowser = goalBrowsers.find(({ name }) => name === 'foo-browser') + + expect(foundBrowser).toEqual({ + ...expectedBrowser, + displayName: 'Custom Foo Browser', + info: 'Loaded from /foo/bar/browser', + custom: true, + version: '9001.1.2.3', + majorVersion: '9001', + path: '/foo/bar/browser', + }) + }) + + it('rejects when there was no matching versionRegex', async () => { + try { + // @ts-expect-error + await detectByPath('/not/a/browser', goalBrowsers) + + throw Error('Should not find a browser') + } catch (err) { + expect(err.notDetectedAtPath).toBe(true) + } + }) + + it('rejects when there was an error executing the command', async () => { + try { + // @ts-expect-error + await detectByPath('/not/a/real/path', goalBrowsers) + throw Error('Should not find a browser') + } catch (err) { + expect(err.notDetectedAtPath).toBe(true) + } + }) + + it('works with spaces in the path', async () => { + // @ts-expect-error + const foundBrowser = await detectByPath('/Applications/My Shiny New Browser.app', goalBrowsers) + + const expectedBrowser = goalBrowsers.find(({ name }) => name === 'foo-browser') + + expect(foundBrowser).toEqual({ + ...expectedBrowser, + displayName: 'Custom Foo Browser', + info: 'Loaded from /Applications/My Shiny New Browser.app', + custom: true, + version: '100.1.2.3', + majorVersion: '100', + path: '/Applications/My Shiny New Browser.app', + }) + }) + }) +}) diff --git a/packages/launcher/test/unit/detect_spec.ts b/packages/launcher/test/unit/detect_spec.ts deleted file mode 100644 index 3dec639cb4e..00000000000 --- a/packages/launcher/test/unit/detect_spec.ts +++ /dev/null @@ -1,174 +0,0 @@ -require('../spec_helper') -import _ from 'lodash' -import { detect, detectByPath, getMajorVersion } from '../../lib/detect' -import { goalBrowsers } from '../fixtures' -import { expect } from 'chai' -import { utils } from '../../lib/utils' -import sinon, { SinonStub } from 'sinon' -import os from 'os' -import { log } from '../log' -import * as linuxHelper from '../../lib/linux' -import * as darwinHelper from '../../lib/darwin' -import * as windowsHelper from '../../lib/windows' -import type { Browser } from '@packages/types' - -const isWindows = () => { - return os.platform() === 'win32' -} - -const stubHelpers = (detect) => { - sinon.stub(linuxHelper, 'detect').callsFake(detect) - sinon.stub(darwinHelper, 'detect').callsFake(detect) - sinon.stub(windowsHelper, 'detect').callsFake(detect) -} - -describe('detect', () => { - // making simple to debug tests - // using DEBUG=... flag - const checkBrowsers = (browsers) => { - log('detected browsers %j', browsers) - expect(browsers).to.be.an('array') - - const mainProps = browsers.map((val) => _.pick(val, ['name', 'version'])) - - log('%d browsers\n%j', browsers.length, mainProps) - - if (isWindows()) { - // we might not find any browsers on Windows CI - expect(browsers.length).to.be.gte(0) - } else { - expect(browsers.length).to.be.gt(0) - } - } - - // we are only going to run tests on platforms with at least - // one browser. This test, is really E2E because it finds - // real browsers - it('detects available browsers', () => { - return detect().then(checkBrowsers) - }) - - describe('#getMajorVersion', () => { - it('parses major version from provided string', () => { - expect(getMajorVersion('123.45.67')).to.eq('123') - expect(getMajorVersion('Browser 77.1.0')).to.eq('Browser 77') - expect(getMajorVersion('999')).to.eq('999') - }) - }) - - describe('#detect', () => { - const testBrowser = { - name: 'test-browser', - family: 'chromium', - channel: 'test-channel', - displayName: 'Test Browser', - versionRegex: /Test Browser (\S+)/m, - binary: 'test-browser-beta', - } - - it('validates browser with own validator property', async () => { - stubHelpers((browser) => { - return Promise.resolve({ - name: browser.name, - path: '/path/to/test-browser', - version: '130', - }) - }) - - const mockValidator = sinon.stub().returns({ isSupported: true }) - - const foundBrowsers = await detect([{ ...testBrowser as Browser, validator: mockValidator }]) - - expect(foundBrowsers).to.have.length(1) - - const foundTestBrowser = foundBrowsers[0] - - expect(foundTestBrowser.name).to.eq('test-browser') - expect(foundTestBrowser.displayName).to.eq('Test Browser') - expect(foundTestBrowser.majorVersion, 'majorVersion').to.eq('130') - expect(foundTestBrowser.unsupportedVersion, 'unsupportedVersion').to.be.undefined - expect(foundTestBrowser.warning, 'warning').to.be.undefined - expect(mockValidator).to.have.been.called - }) - }) - - describe('#detectByPath', () => { - let execa: SinonStub - - beforeEach(() => { - execa = sinon.stub(utils, 'getOutput') - - execa.withArgs('/Applications/My Shiny New Browser.app', ['--version']) - .resolves({ stdout: 'foo-browser v100.1.2.3' }) - - execa.withArgs('/foo/bar/browser', ['--version']) - .resolves({ stdout: 'foo-browser v9001.1.2.3' }) - - execa.withArgs('/not/a/browser', ['--version']) - .resolves({ stdout: 'not a browser version string' }) - - execa.withArgs('/not/a/real/path', ['--version']) - .rejects() - }) - - it('detects by path', () => { - // @ts-ignore - return detectByPath('/foo/bar/browser', goalBrowsers) - .then((browser) => { - expect(browser).to.deep.equal( - Object.assign({}, goalBrowsers.find((gb) => { - return gb.name === 'foo-browser' - }), { - displayName: 'Custom Foo Browser', - info: 'Loaded from /foo/bar/browser', - custom: true, - version: '9001.1.2.3', - majorVersion: '9001', - path: '/foo/bar/browser', - }), - ) - }) - }) - - it('rejects when there was no matching versionRegex', () => { - // @ts-ignore - return detectByPath('/not/a/browser', goalBrowsers) - .then(() => { - throw Error('Should not find a browser') - }) - .catch((err) => { - expect(err.notDetectedAtPath).to.be.true - }) - }) - - it('rejects when there was an error executing the command', () => { - // @ts-ignore - return detectByPath('/not/a/real/path', goalBrowsers) - .then(() => { - throw Error('Should not find a browser') - }) - .catch((err) => { - expect(err.notDetectedAtPath).to.be.true - }) - }) - - it('works with spaces in the path', () => { - // @ts-ignore - return detectByPath('/Applications/My Shiny New Browser.app', goalBrowsers) - .then((browser) => { - expect(browser).to.deep.equal( - Object.assign({}, goalBrowsers.find((gb) => { - return gb.name === 'foo-browser' - }), { - displayName: 'Custom Foo Browser', - info: 'Loaded from /Applications/My Shiny New Browser.app', - custom: true, - version: '100.1.2.3', - majorVersion: '100', - path: '/Applications/My Shiny New Browser.app', - }), - ) - }) - }) - }) -}) diff --git a/packages/launcher/test/unit/linux.spec.ts b/packages/launcher/test/unit/linux.spec.ts new file mode 100644 index 00000000000..e72db123e88 --- /dev/null +++ b/packages/launcher/test/unit/linux.spec.ts @@ -0,0 +1,320 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest' +import _ from 'lodash' +import cp from 'child_process' +import { EventEmitter } from 'events' +import * as linuxHelper from '../../lib/linux' +import { log } from '../log' +import { detect } from '../../lib/detect' +import { goalBrowsers } from '../fixtures' +import os from 'os' +import mockFs from 'mock-fs' + +vi.mock('os', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + platform: vi.fn(), + release: vi.fn(), + homedir: vi.fn(), + }, + } +}) + +vi.mock('child_process', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + spawn: vi.fn(), + }, + } +}) + +describe('linux browser detection', () => { + let cpSpawnCallback: (cmd: string, args: readonly string[], opts, cp: cp.ChildProcess) => void + + beforeEach(() => { + vi.unstubAllEnvs() + vi.resetAllMocks() + + vi.mocked(os.platform).mockReturnValue('linux') + vi.mocked(os.release).mockReturnValue('1.0.0') + + vi.mocked(cp.spawn).mockImplementation((cmd, args, opts) => { + const cpSpawnMock = { + on: vi.fn(), + stdout: new EventEmitter(), + stderr: new EventEmitter(), + kill: vi.fn(), + } + + cpSpawnMock.on.mockImplementation((event: string, callback: (...args: any[]) => void) => { + if (event === 'exit') { + setTimeout(() => callback(), 0) + } + + if (event === 'close') { + setTimeout(() => callback(), 0) + } + }) + + cpSpawnCallback(cmd, args, opts, cpSpawnMock as unknown as cp.ChildProcess) + + return cpSpawnMock as unknown as cp.ChildProcess + }) + }) + + afterEach(() => { + mockFs.restore() + }) + + it('detects browser by running --version', async () => { + const goal = goalBrowsers[0] + + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'test-browser') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'test-browser v100.1.2.3') + }, 0) + } + } + + // @ts-expect-error + const browser = await linuxHelper.detect(goal) + + expect(browser).toEqual({ + name: 'test-browser-name', + path: 'test-browser', + version: '100.1.2.3', + }) + }) + + // https://github.com/cypress-io/cypress/pull/7039 + it('sets profilePath on snapcraft chromium', async () => { + vi.mocked(os.homedir).mockReturnValue('/home/foo') + + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'chromium') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'Chromium 64.2.3 snap') + }, 0) + } + } + + const [browser] = await detect() + + expect(browser).toEqual({ + channel: 'stable', + name: 'chromium', + family: 'chromium', + displayName: 'Chromium', + majorVersion: '64', + path: 'chromium', + profilePath: '/home/foo/snap/chromium/current', + version: '64.2.3', + }) + }) + + // https://github.com/cypress-io/cypress/issues/19793 + describe('sets profilePath on snapcraft firefox', () => { + const expectedSnapFirefox = { + channel: 'stable', + name: 'firefox', + family: 'firefox', + displayName: 'Firefox', + majorVersion: '135', + path: 'firefox', + profilePath: '/home/foo/snap/firefox/current', + version: '135.0.1', + } + + beforeEach(() => { + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'firefox') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'Mozilla Firefox 135.0.1') + }, 0) + } + } + + vi.mocked(os.homedir).mockReturnValue('/home/foo') + }) + + it('with shim script', async () => { + vi.stubEnv('PATH', '/bin') + mockFs({ + '/bin/firefox': mockFs.symlink({ path: '/usr/bin/firefox' }), + '/usr/bin/firefox': mockFs.file({ mode: 0o777, content: 'foo bar foo bar foo bar\nexec /snap/bin/firefox\n' }), + }) + + const [browser] = await detect() + + expect(browser).toEqual(expectedSnapFirefox) + }) + + it('with /snap/bin in path', async () => { + vi.stubEnv('PATH', '/bin:/snap/bin') + mockFs({ + '/snap/bin/firefox': mockFs.file({ mode: 0o777, content: 'binary' }), + }) + + const [browser] = await detect() + + expect(browser).toEqual(expectedSnapFirefox) + }) + + it('with symlink to /snap/bin in path', async () => { + vi.stubEnv('PATH', '/bin') + mockFs({ + '/bin/firefox': mockFs.symlink({ path: '/snap/bin/firefox' }), + '/snap/bin/firefox': mockFs.file({ mode: 0o777, content: 'binary' }), + }) + + const [browser] = await detect() + + expect(browser).toEqual(expectedSnapFirefox) + }) + }) + + // https://github.com/cypress-io/cypress/issues/6669 + it('detects browser if the --version stdout is multiline', async () => { + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'multiline-foo') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', ` + Running without a11y support! + foo-browser v9001.1.2.3 + `) + }, 0) + } + } + + const goal = _.defaults({ binary: 'multiline-foo' }, _.find(goalBrowsers, { name: 'foo-browser' })) + + // @ts-expect-error + const [browser] = await detect([goal]) + + expect(browser).toEqual({ + displayName: 'Foo Browser', + majorVersion: '9001', + name: 'foo-browser', + path: 'multiline-foo', + version: '9001.1.2.3', + }) + }) + + // despite using detect(), this test is in linux/spec instead of detect_spec because it is + // testing side effects that occur within the Linux-specific detect function + // https://github.com/cypress-io/cypress/issues/1400 + it('properly eliminates duplicates', async () => { + const expected = [ + { + displayName: 'Test Browser', + name: 'test-browser-name', + version: '100.1.2.3', + path: 'test-browser', + majorVersion: '100', + }, + { + displayName: 'Foo Browser', + name: 'foo-browser', + version: '100.1.2.3', + path: 'foo-browser', + majorVersion: '100', + }, + ] + + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'test-browser') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'test-browser v100.1.2.3') + }, 0) + } + + if (cmd === 'foo-browser') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'foo-browser v100.1.2.3') + }, 0) + } + } + + // @ts-expect-error + const browsers = await detect(goalBrowsers) + + log('Browsers: %o', browsers) + log('Expected browsers: %o', expected) + expect(browsers).toEqual(expected) + }) + + it('considers multiple binary names', async () => { + const goalBrowsers = [ + { + name: 'foo-browser', + versionRegex: /v(\S+)$/, + binary: ['foo-browser', 'foo-bar-browser'], + }, + ] + + const expected = [ + { + name: 'foo-browser', + version: '100.1.2.3', + path: 'foo-browser', + majorVersion: '100', + }, + ] + + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'foo-browser' || cmd === 'foo-bar-browser') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', 'foo-browser v100.1.2.3') + }, 0) + } + } + + //@ts-expect-error + const browsers = await detect(goalBrowsers) + + log('Browsers: %o', browsers) + log('Expected browsers: %o', expected) + expect(browsers).toEqual(expected) + }) + + describe('#getVersionString', () => { + it('runs the command with `--version` and returns trimmed output', async () => { + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'foo') { + setTimeout(() => { + cpSpawnMock.stdout.emit('data', ' bar ') + }, 0) + } + } + + const versionString = await linuxHelper.getVersionString('foo') + + expect(versionString).toEqual('bar') + }) + + it('rejects with errors', async () => { + const err = new Error() + + cpSpawnCallback = (cmd, args, opts, cpSpawnMock) => { + if (cmd === 'foo') { + // @ts-expect-error - overriding the mock on this method + cpSpawnMock.on.mockImplementation((event: string, callback: (...args: any[]) => void) => { + if (event === 'error') { + setTimeout(() => callback(err), 0) + } + }) + } + } + + await expect(linuxHelper.getVersionString('foo')).rejects.toThrow(err) + }) + }) +}) diff --git a/packages/launcher/test/unit/linux_spec.ts b/packages/launcher/test/unit/linux_spec.ts deleted file mode 100644 index 429894fc9d6..00000000000 --- a/packages/launcher/test/unit/linux_spec.ts +++ /dev/null @@ -1,230 +0,0 @@ -require('../spec_helper') - -import _ from 'lodash' -import * as linuxHelper from '../../lib/linux' -import 'chai-as-promised' -import { log } from '../log' -import { detect } from '../../lib/detect' -import { goalBrowsers } from '../fixtures' -import { expect } from 'chai' -import { utils } from '../../lib/utils' -import os from 'os' -import sinon, { SinonStub } from 'sinon' -import mockFs from 'mock-fs' - -describe('linux browser detection', () => { - let execa: SinonStub - let cachedEnv = { ...process.env } - - beforeEach(() => { - execa = sinon.stub(utils, 'getOutput') - - sinon.stub(os, 'platform').returns('linux') - sinon.stub(os, 'release').returns('1.0.0') - - execa.withArgs('test-browser', ['--version']) - .resolves({ stdout: 'test-browser v100.1.2.3' }) - - execa.withArgs('foo-browser', ['--version']) - .resolves({ stdout: 'foo-browser v100.1.2.3' }) - - execa.withArgs('foo-bar-browser', ['--version']) - .resolves({ stdout: 'foo-browser v100.1.2.3' }) - - execa.withArgs('/foo/bar/browser', ['--version']) - .resolves({ stdout: 'foo-browser v9001.1.2.3' }) - }) - - afterEach(() => { - Object.assign(process.env, cachedEnv) - mockFs.restore() - sinon.restore() - }) - - it('detects browser by running --version', () => { - const goal = goalBrowsers[0] - const checkBrowser = (browser) => { - expect(browser).to.deep.equal({ - name: 'test-browser-name', - path: 'test-browser', - version: '100.1.2.3', - }) - } - - // @ts-ignore - return linuxHelper.detect(goal).then(checkBrowser) - }) - - // https://github.com/cypress-io/cypress/pull/7039 - it('sets profilePath on snapcraft chromium', () => { - execa.withArgs('chromium', ['--version']) - .resolves({ stdout: 'Chromium 64.2.3 snap' }) - - sinon.stub(os, 'homedir').returns('/home/foo') - - const checkBrowser = ([browser]) => { - expect(browser).to.deep.equal({ - channel: 'stable', - name: 'chromium', - family: 'chromium', - displayName: 'Chromium', - majorVersion: '64', - path: 'chromium', - profilePath: '/home/foo/snap/chromium/current', - version: '64.2.3', - }) - } - - return detect().then(checkBrowser) - }) - - // https://github.com/cypress-io/cypress/issues/19793 - context('sets profilePath on snapcraft firefox', () => { - const expectedSnapFirefox = { - channel: 'stable', - name: 'firefox', - family: 'firefox', - displayName: 'Firefox', - majorVersion: '135', - path: 'firefox', - profilePath: '/home/foo/snap/firefox/current', - version: '135.0.1', - } - - beforeEach(() => { - execa.withArgs('firefox', ['--version']) - .resolves({ stdout: 'Mozilla Firefox 135.0.1' }) - - sinon.stub(os, 'homedir').returns('/home/foo') - }) - - it('with shim script', async () => { - process.env.PATH = '/bin' - mockFs({ - '/bin/firefox': mockFs.symlink({ path: '/usr/bin/firefox' }), - '/usr/bin/firefox': mockFs.file({ mode: 0o777, content: 'foo bar foo bar foo bar\nexec /snap/bin/firefox\n' }), - }) - - const [browser] = await detect() - - expect(browser).to.deep.equal(expectedSnapFirefox) - }) - - it('with /snap/bin in path', async () => { - process.env.PATH = '/bin:/snap/bin' - mockFs({ - '/snap/bin/firefox': mockFs.file({ mode: 0o777, content: 'binary' }), - }) - - const [browser] = await detect() - - expect(browser).to.deep.equal(expectedSnapFirefox) - }) - - it('with symlink to /snap/bin in path', async () => { - process.env.PATH = '/bin' - mockFs({ - '/bin/firefox': mockFs.symlink({ path: '/snap/bin/firefox' }), - '/snap/bin/firefox': mockFs.file({ mode: 0o777, content: 'binary' }), - }) - - const [browser] = await detect() - - expect(browser).to.deep.equal(expectedSnapFirefox) - }) - }) - - // https://github.com/cypress-io/cypress/issues/6669 - it('detects browser if the --version stdout is multiline', () => { - execa.withArgs('multiline-foo', ['--version']) - .resolves({ - stdout: ` - Running without a11y support! - foo-browser v9001.1.2.3 - `, - }) - - const goal = _.defaults({ binary: 'multiline-foo' }, _.find(goalBrowsers, { name: 'foo-browser' })) - const checkBrowser = (browser) => { - expect(browser).to.deep.equal({ - name: 'foo-browser', - path: 'multiline-foo', - version: '9001.1.2.3', - }) - } - - // @ts-ignore - return linuxHelper.detect(goal).then(checkBrowser) - }) - - // despite using detect(), this test is in linux/spec instead of detect_spec because it is - // testing side effects that occur within the Linux-specific detect function - // https://github.com/cypress-io/cypress/issues/1400 - it('properly eliminates duplicates', () => { - const expected = [ - { - displayName: 'Test Browser', - name: 'test-browser-name', - version: '100.1.2.3', - path: 'test-browser', - majorVersion: '100', - }, - { - displayName: 'Foo Browser', - name: 'foo-browser', - version: '100.1.2.3', - path: 'foo-browser', - majorVersion: '100', - }, - ] - - // @ts-ignore - return detect(goalBrowsers).then((browsers) => { - log('Browsers: %o', browsers) - log('Expected browsers: %o', expected) - expect(browsers).to.deep.equal(expected) - }) - }) - - it('considers multiple binary names', () => { - const goalBrowsers = [ - { - name: 'foo-browser', - versionRegex: /v(\S+)$/, - binary: ['foo-browser', 'foo-bar-browser'], - }, - ] - - const expected = [ - { - name: 'foo-browser', - version: '100.1.2.3', - path: 'foo-browser', - majorVersion: '100', - }, - ] - - // @ts-ignore - return detect(goalBrowsers).then((browsers) => { - log('Browsers: %o', browsers) - log('Expected browsers: %o', expected) - expect(browsers).to.deep.equal(expected) - }) - }) - - context('#getVersionString', () => { - it('runs the command with `--version` and returns trimmed output', async () => { - execa.withArgs('foo', ['--version']).resolves({ stdout: ' bar ' }) - - expect(await linuxHelper.getVersionString('foo')).to.eq('bar') - }) - - it('rejects with errors', async () => { - const err = new Error() - - execa.withArgs('foo', ['--version']).rejects(err) - - await expect(linuxHelper.getVersionString('foo')).to.be.rejectedWith(err) - }) - }) -}) diff --git a/packages/launcher/test/unit/windows.spec.ts b/packages/launcher/test/unit/windows.spec.ts new file mode 100644 index 00000000000..b7eb3fd2e07 --- /dev/null +++ b/packages/launcher/test/unit/windows.spec.ts @@ -0,0 +1,525 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest' +import winVersionInfo from 'win-version-info' +import _ from 'lodash' +import * as windowsHelper from '../../lib/windows' +import { knownBrowsers } from '../../lib/known-browsers' +import fs from 'fs-extra' +import os from 'os' +import type { Browser } from '@packages/types' +import { detectByPath } from '../../lib/detect' +import { goalBrowsers } from '../fixtures' + +vi.mock('os', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + homedir: vi.fn(), + platform: vi.fn(), + }, + } +}) + +vi.mock('fs-extra', async (importActual) => { + const actual = await importActual() + + return { + default: { + // @ts-expect-error + ...actual.default, + pathExists: vi.fn(), + }, + } +}) + +vi.mock('win-version-info', () => { + return { + default: vi.fn(), + } +}) + +describe('windows browser detection', () => { + const HOMEDIR = 'C:/Users/flotwig' + + let mockBrowsers: { path: string, version: string }[] = [] + + beforeEach(() => { + vi.resetAllMocks() + mockBrowsers = [ + // chrome + { + path: 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe', + version: '1.2.3', + }, + // chromium - 32-bit will be preferred for passivity + { + path: 'C:/Program Files (x86)/Google/chrome-win32/chrome.exe', + version: '2.3.4', + }, + { + path: 'C:/Program Files/Google/chrome-win/chrome.exe', + version: '2.3.4', + }, + // chrome-for-testing - 64-bit will be preferred + { + path: 'C:/Program Files (x86)/Google/Chrome for Testing/chrome.exe', + version: '1.2.3', + }, + { + path: 'C:/Program Files/Google/Chrome for Testing/chrome.exe', + version: '1.2.3', + }, + // chrome beta + { + path: 'C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe', + version: '6.7.8', + }, + // chrome canary is installed in homedir + { + path: `${HOMEDIR}/AppData/Local/Google/Chrome SxS/Application/chrome.exe`, + version: '3.4.5', + }, + // have 32-bit and 64-bit ff - 64-bit will be preferred + { + path: 'C:/Program Files (x86)/Mozilla Firefox/firefox.exe', + version: '72', + }, + { + path: 'C:/Program Files/Mozilla Firefox/firefox.exe', + version: '72', + }, + // 32-bit dev edition + { + path: 'C:/Program Files (x86)/Firefox Developer Edition/firefox.exe', + version: '73', + }, + // 64-bit nightly edition + { + path: 'C:/Program Files/Firefox Nightly/firefox.exe', + version: '74', + }, + { + path: 'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe', + version: '11', + }, + { + path: 'C:/Program Files (x86)/Microsoft/Edge Beta/Application/msedge.exe', + version: '12', + }, + { + path: 'C:/Program Files (x86)/Microsoft/Edge Dev/Application/msedge.exe', + version: '13', + }, + { + // edge canary is installed in homedir + path: `${HOMEDIR}/AppData/Local/Microsoft/Edge SxS/Application/msedge.exe`, + version: '14', + }, + ] + + vi.mocked(os.homedir).mockReturnValue(HOMEDIR) + vi.mocked(os.platform).mockReturnValue('win32') + + vi.mocked(fs.pathExists).mockImplementation((path) => { + const browser = mockBrowsers.find((browser) => windowsHelper.doubleEscape(browser.path) === path) + + if (!browser) { + return Promise.resolve(false) + } + + return Promise.resolve(true) + }) + + vi.mocked(winVersionInfo).mockImplementation((path) => { + const browser = mockBrowsers.find((browser) => windowsHelper.doubleEscape(browser.path) === path) + + if (!browser) { + throw new Error('Browser not found') + } + + return { FileVersion: browser?.version } + }) + }) + + it('detects browsers as expected', async () => { + const mappedBrowsers = [] + + for (const browser of knownBrowsers) { + const foundBrowser = await windowsHelper.detect(browser) + + mappedBrowsers.push({ + ...browser, + ...foundBrowser, + }) + } + + expect(mappedBrowsers).toMatchSnapshot() + }) + + it('detects Chrome Beta 64-bit install', async () => { + // mock installing the 64-bit (32-bit installed already in mockBrowsers) + // should prefer the 64-bit install over the 32-bit install + mockBrowsers.push({ + path: 'C:/Program Files/Google/Chrome Beta/Application/chrome.exe', + version: '9.0.1', + }) + + const chrome = _.find(knownBrowsers, { name: 'chrome', channel: 'beta' })! as Browser + + const foundBrowser = await windowsHelper.detect(chrome) + + const snapshotBrowser = { + ...chrome, + ...foundBrowser, + } + + expect(snapshotBrowser.version).toEqual('9.0.1') + expect(snapshotBrowser).toMatchSnapshot() + }) + + // @see https://github.com/cypress-io/cypress/issues/8425 + it('detects Chrome 64-bit install', async () => { + // mock installing the 64-bit (32-bit installed already in mockBrowsers) + // should prefer the 64-bit install over the 32-bit install + mockBrowsers.push({ + path: 'C:/Program Files/Google/Chrome/Application/chrome.exe', + version: '4.4.4', + }) + + const chrome = _.find(knownBrowsers, { name: 'chrome', channel: 'stable' })! as Browser + + const foundBrowser = await windowsHelper.detect(chrome) + + const snapshotBrowser = { + ...chrome, + ...foundBrowser, + } + + expect(snapshotBrowser.version).toEqual('4.4.4') + expect(snapshotBrowser).toMatchSnapshot() + }) + + it('detects Chrome for Testing 32-bit install', async () => { + // mock uninstalling the 32-bit and 64-bit + const foundCFTInstalls = _.remove(mockBrowsers, (browser) => browser.path.includes('Chrome for Testing')) + + expect(foundCFTInstalls).toHaveLength(2) + + // mock installing the 32-bit + mockBrowsers.push({ + path: 'C:/Program Files (x86)/Google/Chrome for Testing/chrome.exe', + version: '5.5.5', + }) + + const chromeForTesting = _.find(knownBrowsers, { name: 'chrome-for-testing' })! + + const foundBrowser = await windowsHelper.detect(chromeForTesting) + + const snapshotBrowser = { + ...chromeForTesting, + ...foundBrowser, + } + + expect(snapshotBrowser.version).toEqual('5.5.5') + expect(snapshotBrowser).toMatchSnapshot() + }) + + // @see https://github.com/cypress-io/cypress/issues/8432 + it('detects Firefox local installs', async () => { + // mock uninstalling Firefox in the Program Files directory + const foundFirefoxInstalls = _.remove(mockBrowsers, (browser) => browser.path.includes('Firefox')) + + expect(foundFirefoxInstalls).toHaveLength(4) + + // mock installing Firefox in the local app data directory + mockBrowsers.push({ + path: `${HOMEDIR}/AppData/Local/Mozilla Firefox/firefox.exe`, + version: '100', + }) + + mockBrowsers.push({ + path: `${HOMEDIR}/AppData/Local/Firefox Nightly/firefox.exe`, + version: '200', + }) + + mockBrowsers.push({ + path: `${HOMEDIR}/AppData/Local/Firefox Developer Edition/firefox.exe`, + version: '300', + }) + + const firefoxBrowsers = _.filter(knownBrowsers, { family: 'firefox' }) + + const mappedBrowsers = [] + + for (const browser of firefoxBrowsers) { + const foundBrowser = await windowsHelper.detect(browser) + + mappedBrowsers.push({ + ...browser, + ...foundBrowser, + }) + } + + expect(mappedBrowsers.map((browser) => browser.version).sort()).toEqual(['100', '200', '300']) + expect(mappedBrowsers).toMatchSnapshot() + }) + + it('detects Chromium 64-bit install', async () => { + // mock updating the 64-bit install of chrome + const foundChromiumInstalls = _.remove(mockBrowsers, (browser) => browser.path === 'C:/Program Files/Google/chrome-win/chrome.exe') + + expect(foundChromiumInstalls).toHaveLength(1) + + mockBrowsers.push({ + path: 'C:/Program Files/Google/chrome-win/chrome.exe', + version: '6.6.6', + }) + + const chromium = _.find(knownBrowsers, { name: 'chromium' })! + + const foundBrowser = await windowsHelper.detect(chromium) + + const snapshotBrowser = { + ...chromium, + ...foundBrowser, + } + + expect(snapshotBrowser.version).toEqual('6.6.6') + expect(snapshotBrowser).toMatchSnapshot() + }) + + it('detects Chromium 32-bit install in Chromium folder', async () => { + // mock uninstalling the 64-bit and 32-bit in the Google path + const foundChromiumInstalls = _.remove(mockBrowsers, (browser) => browser.path.includes('chrome-win')) + + expect(foundChromiumInstalls).toHaveLength(2) + + // mock installing the 32-bit + mockBrowsers.push({ + path: 'C:/Program Files (x86)/Google/Chromium/chrome.exe', + version: '7.7.7', + }) + + const chromium = _.find(knownBrowsers, { name: 'chromium' })! + + const foundBrowser = await windowsHelper.detect(chromium) + + const snapshotBrowser = { + ...chromium, + ...foundBrowser, + } + + expect(snapshotBrowser.version).toEqual('7.7.7') + expect(snapshotBrowser).toMatchSnapshot() + }) + + it('detects Chromium 64-bit install in Chromium folder', async () => { + // mock uninstalling the 64-bit and 32-bit in the Google path + const foundChromiumInstalls = _.remove(mockBrowsers, (browser) => browser.path.includes('chrome-win')) + + expect(foundChromiumInstalls).toHaveLength(2) + + // mock installing the 32-bit + mockBrowsers.push({ + path: 'C:/Program Files/Google/Chromium/chrome.exe', + version: '8.8.8', + }) + + const chromium = _.find(knownBrowsers, { name: 'chromium' })! + + const foundBrowser = await windowsHelper.detect(chromium) + + const snapshotBrowser = { + ...chromium, + ...foundBrowser, + } + + expect(snapshotBrowser.version).toEqual('8.8.8') + expect(snapshotBrowser).toMatchSnapshot() + }) + + it('works with :browserName format in Windows', async () => { + let path = `${HOMEDIR}/foo/bar/browser.exe` + let win10Path = windowsHelper.doubleEscape(path) + + mockBrowsers.push({ + path, + version: '100', + }) + + const foundBrowser = await detectByPath(`${path}:foo-browser`, goalBrowsers as Browser[]) + + const fooBrowser = goalBrowsers.find(({ name }) => name === 'foo-browser')! + + expect(foundBrowser).toEqual( + { + ...fooBrowser, + displayName: 'Custom Foo Browser', + info: `Loaded from ${win10Path}`, + custom: true, + version: '100', + majorVersion: '100', + path: win10Path, + }, + ) + }) + + it('identifies browser if name in path', async () => { + let path = `${HOMEDIR}/foo/bar/chrome.exe` + let win10Path = windowsHelper.doubleEscape(path) + + mockBrowsers.push({ + path, + version: '100', + }) + + const foundBrowser = await detectByPath(path) + + const chromeBrowser = knownBrowsers.find(({ name }) => name === 'chrome')! + + expect(foundBrowser).toEqual( + { + ...chromeBrowser, + displayName: 'Custom Chrome', + info: `Loaded from ${win10Path}`, + custom: true, + version: '100', + majorVersion: '100', + path: win10Path, + }, + ) + }) + + describe('#getVersionString', () => { + it('returns the FileVersion from win-version-info', async () => { + mockBrowsers.push({ + path: 'foo', + version: 'bar', + }) + + const versionString = await windowsHelper.getVersionString('foo') + + expect(versionString).toEqual('bar') + }) + }) + + describe('#getPathData', () => { + it('returns path and browserKey given path with browser key', () => { + const browserPath = 'C:\\foo\\bar.exe' + const res = windowsHelper.getPathData(`${browserPath}:firefox`) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('firefox') + }) + + it('returns path and browserKey given path with a lot of slashes plus browser key', () => { + const browserPath = 'C:\\\\\\\\foo\\\\\\bar.exe' + const res = windowsHelper.getPathData(`${browserPath}:firefox`) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('firefox') + }) + + it('returns path and browserKey given nix path with browser key', () => { + const browserPath = 'C:/foo/bar.exe' + const res = windowsHelper.getPathData(`${browserPath}:firefox`) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('firefox') + }) + + it('returns path and chrome given just path', () => { + const browserPath = 'C:\\foo\\bar\\chrome.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('chrome') + }) + + it('returns path and chrome given just nix path', () => { + const browserPath = 'C:/foo/bar/chrome.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('chrome') + }) + + it('returns path and edge given just path for edge', () => { + const browserPath = 'C:\\foo\\bar\\edge.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('edge') + }) + + it('returns path and edge given just path for msedge', () => { + const browserPath = 'C:\\foo\\bar\\msedge.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('edge') + }) + + it('returns path and edge given just nix path', () => { + const browserPath = 'C:/foo/bar/edge.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('edge') + }) + + it('returns path and edge given just nix path for msedge', () => { + const browserPath = 'C:/foo/bar/msedge.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('edge') + }) + + it('returns path and firefox given just path', () => { + const browserPath = 'C:\\foo\\bar\\firefox.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('firefox') + }) + + it('returns path and firefox given just nix path', () => { + const browserPath = 'C:/foo/bar/firefox.exe' + const res = windowsHelper.getPathData(browserPath) + + expect(res.path).toEqual(windowsHelper.doubleEscape(browserPath)) + expect(res.browserKey).toEqual('firefox') + }) + }) + + describe('#doubleEscape', () => { + let winPath = 'C:\\\\foo\\\\bar.exe' + + it('converts nix path into double escaped win path', async () => { + let nixPath = 'C:/foo/bar.exe' + + expect(windowsHelper.doubleEscape(nixPath)).toEqual(winPath) + }) + + it('converts win path with different backslash combination into double escaped win path', async () => { + let badWinPath = 'C:\\\\\\\\\\foo\\bar.exe' + + expect(windowsHelper.doubleEscape(badWinPath)).toEqual(winPath) + }) + + it('converts single escaped win path into double escaped win path', async () => { + let badWinPath = 'C:\\foo\\bar.exe' + + expect(windowsHelper.doubleEscape(badWinPath)).toEqual(winPath) + }) + + it('does not affect an already double escaped win path', async () => { + let badWinPath = 'C:\\\\foo\\\\bar.exe' + + expect(windowsHelper.doubleEscape(badWinPath)).toEqual(badWinPath) + }) + }) +}) diff --git a/packages/launcher/test/unit/windows_spec.ts b/packages/launcher/test/unit/windows_spec.ts deleted file mode 100644 index af321beca64..00000000000 --- a/packages/launcher/test/unit/windows_spec.ts +++ /dev/null @@ -1,307 +0,0 @@ -import _ from 'lodash' -import { expect } from 'chai' -import * as windowsHelper from '../../lib/windows' -import { normalize } from 'path' -import sinon, { SinonStub } from 'sinon' -import { knownBrowsers } from '../../lib/known-browsers' -import Bluebird from 'bluebird' -import fse from 'fs-extra' -import os from 'os' -import snapshot from 'snap-shot-it' -import type { Browser } from '@packages/types' -import { detectByPath } from '../../lib/detect' -import { goalBrowsers } from '../fixtures' - -function stubBrowser (path: string, version: string) { - path = windowsHelper.doubleEscape(normalize(path)) - - ;(windowsHelper.getVersionString as unknown as SinonStub) - .withArgs(path) - .resolves(version) - - ;(fse.pathExists as SinonStub) - .withArgs(path) - .resolves(true) -} - -function detect (goalBrowsers: Browser[]) { - return Bluebird.mapSeries(goalBrowsers, (browser) => { - return windowsHelper.detect(browser) - .then((foundBrowser) => { - return _.merge(browser, foundBrowser) - }) - }) -} - -const HOMEDIR = 'C:/Users/flotwig' - -describe('windows browser detection', () => { - beforeEach(() => { - sinon.stub(fse, 'pathExists').resolves(false) - sinon.stub(os, 'homedir').returns(HOMEDIR) - sinon.stub(windowsHelper, 'getVersionString').rejects() - }) - - it('detects browsers as expected', async () => { - // chrome - stubBrowser('C:/Program Files (x86)/Google/Chrome/Application/chrome.exe', '1.2.3') - // chromium - 32-bit will be preferred for passivity - stubBrowser('C:/Program Files (x86)/Google/chrome-win32/chrome.exe', '2.3.4') - stubBrowser('C:/Program Files/Google/chrome-win/chrome.exe', '2.3.4') - - // chrome-for-testing - 64-bit will be preferred - stubBrowser('C:/Program Files (x86)/Google/Chrome for Testing/chrome.exe', '1.2.3') - stubBrowser('C:/Program Files/Google/Chrome for Testing/chrome.exe', '1.2.3') - - // chrome beta - stubBrowser('C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe', '6.7.8') - - // chrome canary is installed in homedir - stubBrowser(`${HOMEDIR}/AppData/Local/Google/Chrome SxS/Application/chrome.exe`, '3.4.5') - - // have 32-bit and 64-bit ff - 64-bit will be preferred - stubBrowser('C:/Program Files (x86)/Mozilla Firefox/firefox.exe', '72') - stubBrowser('C:/Program Files/Mozilla Firefox/firefox.exe', '72') - - // 32-bit dev edition - stubBrowser('C:/Program Files (x86)/Firefox Developer Edition/firefox.exe', '73') - - // 64-bit nightly edition - stubBrowser('C:/Program Files/Firefox Nightly/firefox.exe', '74') - - stubBrowser('C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe', '11') - stubBrowser('C:/Program Files (x86)/Microsoft/Edge Beta/Application/msedge.exe', '12') - stubBrowser('C:/Program Files (x86)/Microsoft/Edge Dev/Application/msedge.exe', '13') - - // edge canary is installed in homedir - stubBrowser(`${HOMEDIR}/AppData/Local/Microsoft/Edge SxS/Application/msedge.exe`, '14') - - snapshot(await detect(knownBrowsers)) - }) - - it('detects Chrome Beta 64-bit install', async () => { - stubBrowser('C:/Program Files/Google/Chrome Beta/Application/chrome.exe', '9.0.1') - const chrome = _.find(knownBrowsers, { name: 'chrome', channel: 'beta' })! - - snapshot(await detect([chrome])) - }) - - // @see https://github.com/cypress-io/cypress/issues/8425 - it('detects Chrome 64-bit install', async () => { - stubBrowser('C:/Program Files/Google/Chrome/Application/chrome.exe', '4.4.4') - const chrome = _.find(knownBrowsers, { name: 'chrome', channel: 'stable' })! - - snapshot(await detect([chrome])) - }) - - it('detects Chrome for Testing 32-bit install', async () => { - stubBrowser('C:/Program Files (x86)/Google/Chrome for Testing/chrome.exe', '5.5.5') - const chromeForTesting = _.find(knownBrowsers, { name: 'chrome-for-testing' })! - - snapshot(await detect([chromeForTesting])) - }) - - // @see https://github.com/cypress-io/cypress/issues/8432 - it('detects Firefox local installs', async () => { - stubBrowser(`${HOMEDIR}/AppData/Local/Mozilla Firefox/firefox.exe`, '100') - stubBrowser(`${HOMEDIR}/AppData/Local/Firefox Nightly/firefox.exe`, '200') - stubBrowser(`${HOMEDIR}/AppData/Local/Firefox Developer Edition/firefox.exe`, '300') - - const firefoxes = _.filter(knownBrowsers, { family: 'firefox' }) - - snapshot(await detect(firefoxes)) - }) - - it('detects Chromium 64-bit install', async () => { - stubBrowser('C:/Program Files/Google/chrome-win/chrome.exe', '6.6.6') - const chromium = _.find(knownBrowsers, { name: 'chromium' })! - - snapshot(await detect([chromium])) - }) - - it('detects Chromium 32-bit install in Chromium folder', async () => { - stubBrowser('C:/Program Files (x86)/Google/Chromium/chrome.exe', '7.7.7') - const chromium = _.find(knownBrowsers, { name: 'chromium' })! - - snapshot(await detect([chromium])) - }) - - it('detects Chromium 64-bit install in Chromium folder', async () => { - stubBrowser('C:/Program Files/Google/Chromium/chrome.exe', '8.8.8') - const chromium = _.find(knownBrowsers, { name: 'chromium' })! - - snapshot(await detect([chromium])) - }) - - it('works with :browserName format in Windows', () => { - sinon.stub(os, 'platform').returns('win32') - let path = `${HOMEDIR}/foo/bar/browser.exe` - let win10Path = windowsHelper.doubleEscape(path) - - stubBrowser(path, '100') - - return detectByPath(`${path}:foo-browser`, goalBrowsers as Browser[]).then((browser) => { - expect(browser).to.deep.equal( - Object.assign({}, goalBrowsers.find((gb) => { - return gb.name === 'foo-browser' - }), { - displayName: 'Custom Foo Browser', - info: `Loaded from ${win10Path}`, - custom: true, - version: '100', - majorVersion: '100', - path: win10Path, - }), - ) - }) - }) - - it('identifies browser if name in path', async () => { - sinon.stub(os, 'platform').returns('win32') - let path = `${HOMEDIR}/foo/bar/chrome.exe` - let win10Path = windowsHelper.doubleEscape(path) - - stubBrowser(path, '100') - - return detectByPath(path).then((browser) => { - expect(browser).to.deep.equal( - Object.assign({}, knownBrowsers.find((gb) => { - return gb.name === 'chrome' - }), { - displayName: 'Custom Chrome', - info: `Loaded from ${win10Path}`, - custom: true, - version: '100', - majorVersion: '100', - path: win10Path, - }), - ) - }) - }) - - context('#getVersionString', () => { - it('returns the FileVersion from win-version-info', async () => { - stubBrowser('foo', 'bar') - - expect(await windowsHelper.getVersionString('foo')).to.eq('bar') - }) - }) - - context('#getPathData', () => { - it('returns path and browserKey given path with browser key', () => { - const browserPath = 'C:\\foo\\bar.exe' - const res = windowsHelper.getPathData(`${browserPath}:firefox`) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('firefox') - }) - - it('returns path and browserKey given path with a lot of slashes plus browser key', () => { - const browserPath = 'C:\\\\\\\\foo\\\\\\bar.exe' - const res = windowsHelper.getPathData(`${browserPath}:firefox`) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('firefox') - }) - - it('returns path and browserKey given nix path with browser key', () => { - const browserPath = 'C:/foo/bar.exe' - const res = windowsHelper.getPathData(`${browserPath}:firefox`) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('firefox') - }) - - it('returns path and chrome given just path', () => { - const browserPath = 'C:\\foo\\bar\\chrome.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('chrome') - }) - - it('returns path and chrome given just nix path', () => { - const browserPath = 'C:/foo/bar/chrome.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('chrome') - }) - - it('returns path and edge given just path for edge', () => { - const browserPath = 'C:\\foo\\bar\\edge.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('edge') - }) - - it('returns path and edge given just path for msedge', () => { - const browserPath = 'C:\\foo\\bar\\msedge.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('edge') - }) - - it('returns path and edge given just nix path', () => { - const browserPath = 'C:/foo/bar/edge.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('edge') - }) - - it('returns path and edge given just nix path for msedge', () => { - const browserPath = 'C:/foo/bar/msedge.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('edge') - }) - - it('returns path and firefox given just path', () => { - const browserPath = 'C:\\foo\\bar\\firefox.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('firefox') - }) - - it('returns path and firefox given just nix path', () => { - const browserPath = 'C:/foo/bar/firefox.exe' - const res = windowsHelper.getPathData(browserPath) - - expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath)) - expect(res.browserKey).to.eq('firefox') - }) - }) - - context('#doubleEscape', () => { - let winPath = 'C:\\\\foo\\\\bar.exe' - - it('converts nix path into double escaped win path', async () => { - let nixPath = 'C:/foo/bar.exe' - - expect(windowsHelper.doubleEscape(nixPath)).to.eq(winPath) - }) - - it('converts win path with different backslash combination into double escaped win path', async () => { - let badWinPath = 'C:\\\\\\\\\\foo\\bar.exe' - - expect(windowsHelper.doubleEscape(badWinPath)).to.eq(winPath) - }) - - it('converts single escaped win path into double escaped win path', async () => { - let badWinPath = 'C:\\foo\\bar.exe' - - expect(windowsHelper.doubleEscape(badWinPath)).to.eq(winPath) - }) - - it('does not affect an already double escaped win path', async () => { - let badWinPath = 'C:\\\\foo\\\\bar.exe' - - expect(windowsHelper.doubleEscape(badWinPath)).to.eq(badWinPath) - }) - }) -}) diff --git a/packages/launcher/vitest.config.ts b/packages/launcher/vitest.config.ts new file mode 100644 index 00000000000..1a9a321880f --- /dev/null +++ b/packages/launcher/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + include: ['test/**/*.spec.ts'], + globals: true, + environment: 'node', + }, +}) diff --git a/yarn.lock b/yarn.lock index 95b3ccddd05..238372df1ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7107,7 +7107,7 @@ resolved "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" integrity sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg== -"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2", "@sinonjs/commons@^1.8.1", "@sinonjs/commons@^1.8.3": +"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2", "@sinonjs/commons@^1.8.3": version "1.8.6" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== @@ -7205,7 +7205,7 @@ lodash.get "^4.4.2" type-detect "^4.0.8" -"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.0.3", "@sinonjs/samsam@^5.3.1": +"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.0.3": version "5.3.1" resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.1.tgz#375a45fe6ed4e92fca2fb920e007c48232a6507f" integrity sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg== @@ -24494,7 +24494,7 @@ nise@^3.0.1: lolex "^5.0.1" path-to-regexp "^1.7.0" -nise@^4.0.1, nise@^4.1.0: +nise@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA== @@ -29683,18 +29683,6 @@ sinon@8.1.1: nise "^3.0.1" supports-color "^7.1.0" -sinon@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-10.0.0.tgz#52279f97e35646ff73d23207d0307977c9b81430" - integrity sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw== - dependencies: - "@sinonjs/commons" "^1.8.1" - "@sinonjs/fake-timers" "^6.0.1" - "@sinonjs/samsam" "^5.3.1" - diff "^4.0.2" - nise "^4.1.0" - supports-color "^7.1.0" - sinon@^9.0.0: version "9.0.2" resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.2.tgz#b9017e24633f4b1c98dfb6e784a5f0509f5fd85d"