]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Partially revert "Remove BrowserStack"
authorXhmikosR <xhmikosr@gmail.com>
Wed, 12 Apr 2023 15:38:58 +0000 (18:38 +0300)
committerXhmikosR <xhmikosr@gmail.com>
Thu, 7 Mar 2024 15:38:59 +0000 (17:38 +0200)
.github/workflows/browserstack.yml [new file with mode: 0644]
.github/workflows/lambdatest.yml
js/tests/browsers.js
js/tests/karma.conf.js
package-lock.json
package.json

diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml
new file mode 100644 (file)
index 0000000..a53c233
--- /dev/null
@@ -0,0 +1,46 @@
+name: BrowserStack
+
+on:
+  push:
+    branches:
+      - "**"
+      - "!dependabot/**"
+  workflow_dispatch:
+
+env:
+  FORCE_COLOR: 2
+  NODE: 20
+
+permissions:
+  contents: read
+
+jobs:
+  browserstack:
+    runs-on: ubuntu-latest
+    if: github.repository == 'twbs/bootstrap'
+    timeout-minutes: 30
+
+    steps:
+      - name: Clone repository
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: false
+
+      - name: Set up Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: "${{ env.NODE }}"
+          cache: npm
+
+      - name: Install npm dependencies
+        run: npm ci
+
+      - name: Run dist
+        run: npm run dist
+
+      - name: Run BrowserStack tests
+        run: npm run js-test-cloud
+        env:
+          BROWSER_STACK_ACCESS_KEY: "${{ secrets.BROWSER_STACK_ACCESS_KEY }}"
+          BROWSER_STACK_USERNAME: "${{ secrets.BROWSER_STACK_USERNAME }}"
+          GITHUB_SHA: "${{ github.sha }}"
index c81ffe237a0e72b55ddb0e0fce4fffc9f9b5d50b..c0975b85dc39c78c36f572acff6051e82494816b 100644 (file)
@@ -39,7 +39,7 @@ jobs:
         run: npm run dist
 
       - name: Run LambdaTest tests
-        run: npm run js-test-cloud
+        run: npm run js-test-lt-cloud
         env:
           LT_USERNAME: "${{ secrets.LT_USERNAME }}"
           LT_ACCESS_KEY: "${{ secrets.LT_ACCESS_KEY }}"
index a73143dde857d0b9aa7794f9096daba3e7b5617d..bb72f54a8e91ebe4aef9dcaa11162cec41cb19c4 100644 (file)
+/* eslint-disable camelcase */
+
 'use strict'
 
 const browsers = {
-  safariMac: {
-    browserName: 'Safari',
-    browserVersion: 'latest',
-    'LT:Options': {
-      platformName: 'MacOS Monterey'
-    }
-  },
-  chromeMac: {
-    browserName: 'Chrome',
-    browserVersion: 'latest',
-    'LT:Options': {
-      platformName: 'MacOS Monterey'
-    }
-  },
-  firefoxMac: {
-    browserName: 'Firefox',
-    browserVersion: 'latest',
-    'LT:Options': {
-      platformName: 'MacOS Monterey'
-    }
-  },
-  chromeWin10: {
-    browserName: 'Chrome',
-    browserVersion: '60',
-    'LT:Options': {
-      platformName: 'Windows 10'
+  lambdaTest: {
+    safariMac: {
+      browserName: 'Safari',
+      browserVersion: 'latest',
+      'LT:Options': {
+        platformName: 'MacOS Monterey'
+      }
+    },
+    chromeMac: {
+      browserName: 'Chrome',
+      browserVersion: 'latest',
+      'LT:Options': {
+        platformName: 'MacOS Monterey'
+      }
+    },
+    firefoxMac: {
+      browserName: 'Firefox',
+      browserVersion: 'latest',
+      'LT:Options': {
+        platformName: 'MacOS Monterey'
+      }
+    },
+    chromeWin10: {
+      browserName: 'Chrome',
+      browserVersion: '60',
+      'LT:Options': {
+        platformName: 'Windows 10'
+      }
+    },
+    firefoxWin10: {
+      browserName: 'Firefox',
+      browserVersion: '60',
+      'LT:Options': {
+        platformName: 'Windows 10'
+      }
+    },
+    chromeWin10Latest: {
+      browserName: 'Chrome',
+      browserVersion: 'latest',
+      'LT:Options': {
+        platformName: 'Windows 10'
+      }
+    },
+    firefoxWin10Latest: {
+      browserName: 'Firefox',
+      browserVersion: 'latest',
+      'LT:Options': {
+        platformName: 'Windows 10'
+      }
+    },
+    iphone11: {
+      platformName: 'ios',
+      platformVersion: '15',
+      browserName: 'Safari',
+      deviceName: 'iPhone 13',
+      isRealMobile: true
+    },
+    iphone14: {
+      platformName: 'ios',
+      platformVersion: '16',
+      browserName: 'Safari',
+      deviceName: 'iPhone 14',
+      isRealMobile: true
+    },
+    pixel6: {
+      platformName: 'android',
+      platformVersion: '12',
+      browserName: 'Chrome',
+      deviceName: 'Pixel 6',
+      isRealMobile: true
     }
   },
-  firefoxWin10: {
-    browserName: 'Firefox',
-    browserVersion: '60',
-    'LT:Options': {
-      platformName: 'Windows 10'
+  browserStack: {
+    safariMac: {
+      base: 'BrowserStack',
+      os: 'OS X',
+      os_version: 'Catalina',
+      browser: 'Safari',
+      browser_version: 'latest'
+    },
+    chromeMac: {
+      base: 'BrowserStack',
+      os: 'OS X',
+      os_version: 'Catalina',
+      browser: 'Chrome',
+      browser_version: 'latest'
+    },
+    firefoxMac: {
+      base: 'BrowserStack',
+      os: 'OS X',
+      os_version: 'Catalina',
+      browser: 'Firefox',
+      browser_version: 'latest'
+    },
+    chromeWin10: {
+      base: 'BrowserStack',
+      os: 'Windows',
+      os_version: '10',
+      browser: 'Chrome',
+      browser_version: '60'
+    },
+    firefoxWin10: {
+      base: 'BrowserStack',
+      os: 'Windows',
+      os_version: '10',
+      browser: 'Firefox',
+      browser_version: '60'
+    },
+    chromeWin10Latest: {
+      base: 'BrowserStack',
+      os: 'Windows',
+      os_version: '10',
+      browser: 'Chrome',
+      browser_version: 'latest'
+    },
+    firefoxWin10Latest: {
+      base: 'BrowserStack',
+      os: 'Windows',
+      os_version: '10',
+      browser: 'Firefox',
+      browser_version: 'latest'
+    },
+    iphone7: {
+      base: 'BrowserStack',
+      os: 'ios',
+      os_version: '12.0',
+      device: 'iPhone 7',
+      real_mobile: true
+    },
+    iphone12: {
+      base: 'BrowserStack',
+      os: 'ios',
+      os_version: '14.0',
+      device: 'iPhone 12',
+      real_mobile: true
+    },
+    pixel2: {
+      base: 'BrowserStack',
+      os: 'android',
+      os_version: '8.0',
+      device: 'Google Pixel 2',
+      real_mobile: true
     }
-  },
-  chromeWin10Latest: {
-    browserName: 'Chrome',
-    browserVersion: 'latest',
-    'LT:Options': {
-      platformName: 'Windows 10'
-    }
-  },
-  firefoxWin10Latest: {
-    browserName: 'Firefox',
-    browserVersion: 'latest',
-    'LT:Options': {
-      platformName: 'Windows 10'
-    }
-  },
-  iphone11: {
-    platformName: 'ios',
-    platformVersion: '15',
-    browserName: 'Safari',
-    deviceName: 'iPhone 13',
-    isRealMobile: true
-  },
-  iphone14: {
-    platformName: 'ios',
-    platformVersion: '16',
-    browserName: 'Safari',
-    deviceName: 'iPhone 14',
-    isRealMobile: true
-  },
-  pixel6: {
-    platformName: 'android',
-    platformVersion: '12',
-    browserName: 'Chrome',
-    deviceName: 'Pixel 6',
-    isRealMobile: true
   }
 }
 
index c3eecc1a35af30cd292ef3866c0793e3e99b41f8..cb41b1e48f78dc459b70e8d77a0496aa7dc0a979 100644 (file)
@@ -10,6 +10,7 @@ const { browsers } = require('./browsers.js')
 
 const ENV = process.env
 const LAMBDATEST = Boolean(ENV.LAMBDATEST)
+const BROWSERSTACK = Boolean(ENV.BROWSERSTACK)
 const DEBUG = Boolean(ENV.DEBUG)
 const JQUERY_TEST = Boolean(ENV.JQUERY)
 
@@ -79,7 +80,7 @@ const config = {
     'node_modules/hammer-simulator/index.js',
     {
       pattern: 'js/tests/unit/**/!(jquery).spec.js',
-      watched: !LAMBDATEST
+      watched: !BROWSERSTACK && !LAMBDATEST
     }
   ],
   preprocessors: {
@@ -118,38 +119,51 @@ const config = {
 if (LAMBDATEST) {
   config.hostname = 'localhost.lambdatest.com'
 
-  for (const key of Object.keys(browsers)) {
-    browsers[key].base = 'WebDriver'
-    browsers[key].build = `bootstrap-${ENV.GITHUB_SHA ? `${ENV.GITHUB_SHA.slice(0, 7)}-` : ''}${new Date().toISOString()}`
-    browsers[key].project = 'Bootstrap'
-
-    if (browsers[key].isRealMobile) {
-      browsers[key].config = webdriverConfigMobile
-      browsers[key].user = ENV.LT_USERNAME
-      browsers[key].accessKey = ENV.LT_ACCESS_KEY
-      browsers[key].tunnel = true
-      browsers[key].console = true
-      browsers[key].network = true
-      browsers[key].tunnelName = process.env.LT_TUNNEL_NAME || 'jasmine'
-      browsers[key].pseudoActivityInterval = 5000 // 5000 ms heartbeat
+  for (const key of Object.keys(browsers.lambdaTest)) {
+    browsers.lambdaTest[key].base = 'WebDriver'
+    browsers.lambdaTest[key].build = `bootstrap-${ENV.GITHUB_SHA ? `${ENV.GITHUB_SHA.slice(0, 7)}-` : ''}${new Date().toISOString()}`
+    browsers.lambdaTest[key].project = 'Bootstrap'
+
+    if (browsers.lambdaTest[key].isRealMobile) {
+      browsers.lambdaTest[key].config = webdriverConfigMobile
+      browsers.lambdaTest[key].user = ENV.LT_USERNAME
+      browsers.lambdaTest[key].accessKey = ENV.LT_ACCESS_KEY
+      browsers.lambdaTest[key].tunnel = true
+      browsers.lambdaTest[key].console = true
+      browsers.lambdaTest[key].network = true
+      browsers.lambdaTest[key].tunnelName = process.env.LT_TUNNEL_NAME || 'jasmine'
+      browsers.lambdaTest[key].pseudoActivityInterval = 5000 // 5000 ms heartbeat
     } else {
-      browsers[key].config = webdriverConfig
-      browsers[key]['LT:Options'].username = ENV.LT_USERNAME
-      browsers[key]['LT:Options'].accessKey = ENV.LT_ACCESS_KEY
-      browsers[key]['LT:Options'].tunnel = true
-      browsers[key]['LT:Options'].console = true
-      browsers[key]['LT:Options'].network = true
-      browsers[key]['LT:Options'].tunnelName = process.env.LT_TUNNEL_NAME || 'jasmine'
-      browsers[key]['LT:Options'].pseudoActivityInterval = 5000 // 5000 ms heartbeat
+      browsers.lambdaTest[key].config = webdriverConfig
+      browsers.lambdaTest[key]['LT:Options'].username = ENV.LT_USERNAME
+      browsers.lambdaTest[key]['LT:Options'].accessKey = ENV.LT_ACCESS_KEY
+      browsers.lambdaTest[key]['LT:Options'].tunnel = true
+      browsers.lambdaTest[key]['LT:Options'].console = true
+      browsers.lambdaTest[key]['LT:Options'].network = true
+      browsers.lambdaTest[key]['LT:Options'].tunnelName = process.env.LT_TUNNEL_NAME || 'jasmine'
+      browsers.lambdaTest[key]['LT:Options'].pseudoActivityInterval = 5000 // 5000 ms heartbeat
     }
 
-    browsers[key].retryLimit = 3
+    browsers.lambdaTest[key].retryLimit = 3
   }
 
   plugins.push('karma-webdriver-launcher', 'karma-jasmine-html-reporter')
-  config.customLaunchers = browsers
-  config.browsers = Object.keys(browsers)
+  config.customLaunchers = browsers.lambdaTest
+  config.browsers = Object.keys(browsers.lambdaTest)
   reporters.push('kjhtml')
+} else if (BROWSERSTACK) {
+  config.hostname = ip.address()
+  config.browserStack = {
+    username: ENV.BROWSER_STACK_USERNAME,
+    accessKey: ENV.BROWSER_STACK_ACCESS_KEY,
+    build: `bootstrap-${ENV.GITHUB_SHA ? `${ENV.GITHUB_SHA.slice(0, 7)}-` : ''}${new Date().toISOString()}`,
+    project: 'Bootstrap',
+    retryLimit: 3
+  }
+  plugins.push('karma-browserstack-launcher', 'karma-jasmine-html-reporter')
+  config.customLaunchers = browsers.browserStack
+  config.browsers = Object.keys(browsers.browserStack)
+  reporters.push('BrowserStack', 'kjhtml')
 } else if (JQUERY_TEST) {
   frameworks.push('detectBrowsers')
   plugins.push(
index 95e2abff95056488d23b5f080fc2eb7cd37a6e62..b320544f24ffa2c3477dddf4eb18dd0195d5ec2e 100644 (file)
@@ -46,6 +46,7 @@
         "jasmine": "^5.1.0",
         "jquery": "^3.7.1",
         "karma": "^6.4.3",
+        "karma-browserstack-launcher": "^1.6.0",
         "karma-chrome-launcher": "^3.2.0",
         "karma-coverage-istanbul-reporter": "^3.0.3",
         "karma-detect-browsers": "^2.3.3",
         "unzipper": "^0.10.5"
       }
     },
-    "node_modules/@lambdatest/node-tunnel/node_modules/agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
-      "dev": true,
-      "dependencies": {
-        "debug": "4"
-      },
-      "engines": {
-        "node": ">= 6.0.0"
-      }
-    },
     "node_modules/@lambdatest/node-tunnel/node_modules/axios": {
       "version": "0.26.1",
       "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
+    "node_modules/agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
         "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
       }
     },
+    "node_modules/browserstack": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz",
+      "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==",
+      "dev": true,
+      "dependencies": {
+        "https-proxy-agent": "^2.2.1"
+      }
+    },
+    "node_modules/browserstack-local": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.5.5.tgz",
+      "integrity": "sha512-jKne7yosrMcptj3hqxp36TP9k0ZW2sCqhyurX24rUL4G3eT7OLgv+CSQN8iq5dtkv5IK+g+v8fWvsiC/S9KxMg==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^6.0.2",
+        "https-proxy-agent": "^5.0.1",
+        "is-running": "^2.1.0",
+        "ps-tree": "=1.2.0",
+        "temp-fs": "^0.9.9"
+      }
+    },
+    "node_modules/browserstack-local/node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/es6-promise": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+      "dev": true
+    },
+    "node_modules/es6-promisify": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+      "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
+      "dev": true,
+      "dependencies": {
+        "es6-promise": "^4.0.3"
+      }
+    },
     "node_modules/escalade": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
         "node": ">=0.10.0"
       }
     },
+    "node_modules/event-stream": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+      "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+      "dev": true,
+      "dependencies": {
+        "duplexer": "~0.1.1",
+        "from": "~0",
+        "map-stream": "~0.1.0",
+        "pause-stream": "0.0.11",
+        "split": "0.3",
+        "stream-combiner": "~0.0.4",
+        "through": "~2.3.1"
+      }
+    },
+    "node_modules/event-stream/node_modules/split": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+      "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+      "dev": true,
+      "dependencies": {
+        "through": "2"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/eventemitter3": {
       "version": "4.0.7",
       "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
         "url": "https://github.com/sponsors/rawify"
       }
     },
+    "node_modules/from": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+      "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+      "dev": true
+    },
     "node_modules/fs-constants": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
         "node": ">=10.19.0"
       }
     },
+    "node_modules/https-proxy-agent": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+      "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^4.3.0",
+        "debug": "^3.1.0"
+      },
+      "engines": {
+        "node": ">= 4.5.0"
+      }
+    },
+    "node_modules/https-proxy-agent/node_modules/agent-base": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+      "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+      "dev": true,
+      "dependencies": {
+        "es6-promisify": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/https-proxy-agent/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
     "node_modules/hugo-bin": {
       "version": "0.120.7",
       "resolved": "https://registry.npmjs.org/hugo-bin/-/hugo-bin-0.120.7.tgz",
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-running": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz",
+      "integrity": "sha512-mjJd3PujZMl7j+D395WTIO5tU5RIDBfVSRtRR4VOJou3H66E38UjbjvDGh3slJzPuolsb+yQFqwHNNdyp5jg3w==",
+      "dev": true
+    },
     "node_modules/is-shared-array-buffer": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
         "node": ">= 10"
       }
     },
+    "node_modules/karma-browserstack-launcher": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/karma-browserstack-launcher/-/karma-browserstack-launcher-1.6.0.tgz",
+      "integrity": "sha512-Y/UWPdHZkHIVH2To4GWHCTzmrsB6H7PBWy6pw+TWz5sr4HW2mcE+Uj6qWgoVNxvQU1Pfn5LQQzI6EQ65p8QbiQ==",
+      "dev": true,
+      "dependencies": {
+        "browserstack": "~1.5.1",
+        "browserstack-local": "^1.3.7",
+        "q": "~1.5.0"
+      },
+      "peerDependencies": {
+        "karma": ">=0.9"
+      }
+    },
     "node_modules/karma-chrome-launcher": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz",
         "semver": "bin/semver"
       }
     },
+    "node_modules/map-stream": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+      "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+      "dev": true
+    },
     "node_modules/mathml-tag-names": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
         "node": ">=8"
       }
     },
+    "node_modules/pause-stream": {
+      "version": "0.0.11",
+      "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+      "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+      "dev": true,
+      "dependencies": {
+        "through": "~2.3"
+      }
+    },
     "node_modules/peek-readable": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
       "dev": true
     },
+    "node_modules/ps-tree": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz",
+      "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==",
+      "dev": true,
+      "dependencies": {
+        "event-stream": "=3.3.4"
+      },
+      "bin": {
+        "ps-tree": "bin/ps-tree.js"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/psl": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
         "node": ">= 0.6"
       }
     },
+    "node_modules/stream-combiner": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+      "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+      "dev": true,
+      "dependencies": {
+        "duplexer": "~0.1.1"
+      }
+    },
     "node_modules/streamroller": {
       "version": "3.1.5",
       "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz",
         "streamx": "^2.15.0"
       }
     },
+    "node_modules/temp-fs": {
+      "version": "0.9.9",
+      "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz",
+      "integrity": "sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==",
+      "dev": true,
+      "dependencies": {
+        "rimraf": "~2.5.2"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/temp-fs/node_modules/rimraf": {
+      "version": "2.5.4",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz",
+      "integrity": "sha512-Lw7SHMjssciQb/rRz7JyPIy9+bbUshEucPoLRvWqy09vC5zQixl8Uet+Zl+SROBB/JMWHJRdCk1qdxNWHNMvlQ==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.0.5"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      }
+    },
     "node_modules/terser": {
       "version": "5.27.2",
       "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.2.tgz",
         "unzipper": "^0.10.5"
       },
       "dependencies": {
-        "agent-base": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-          "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
-          "dev": true,
-          "requires": {
-            "debug": "4"
-          }
-        },
         "axios": {
           "version": "0.26.1",
           "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
       "dev": true,
       "requires": {}
     },
+    "agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "requires": {
+        "debug": "4"
+      }
+    },
     "ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
         "update-browserslist-db": "^1.0.13"
       }
     },
+    "browserstack": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz",
+      "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==",
+      "dev": true,
+      "requires": {
+        "https-proxy-agent": "^2.2.1"
+      }
+    },
+    "browserstack-local": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.5.5.tgz",
+      "integrity": "sha512-jKne7yosrMcptj3hqxp36TP9k0ZW2sCqhyurX24rUL4G3eT7OLgv+CSQN8iq5dtkv5IK+g+v8fWvsiC/S9KxMg==",
+      "dev": true,
+      "requires": {
+        "agent-base": "^6.0.2",
+        "https-proxy-agent": "^5.0.1",
+        "is-running": "^2.1.0",
+        "ps-tree": "=1.2.0",
+        "temp-fs": "^0.9.9"
+      },
+      "dependencies": {
+        "https-proxy-agent": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+          "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+          "dev": true,
+          "requires": {
+            "agent-base": "6",
+            "debug": "4"
+          }
+        }
+      }
+    },
     "buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
         "is-symbol": "^1.0.2"
       }
     },
+    "es6-promise": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+      "dev": true
+    },
+    "es6-promisify": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+      "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
+      "dev": true,
+      "requires": {
+        "es6-promise": "^4.0.3"
+      }
+    },
     "escalade": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
       "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
       "dev": true
     },
+    "event-stream": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+      "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+      "dev": true,
+      "requires": {
+        "duplexer": "~0.1.1",
+        "from": "~0",
+        "map-stream": "~0.1.0",
+        "pause-stream": "0.0.11",
+        "split": "0.3",
+        "stream-combiner": "~0.0.4",
+        "through": "~2.3.1"
+      },
+      "dependencies": {
+        "split": {
+          "version": "0.3.3",
+          "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+          "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+          "dev": true,
+          "requires": {
+            "through": "2"
+          }
+        }
+      }
+    },
     "eventemitter3": {
       "version": "4.0.7",
       "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
       "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
       "dev": true
     },
+    "from": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+      "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+      "dev": true
+    },
     "fs-constants": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
         "resolve-alpn": "^1.2.0"
       }
     },
+    "https-proxy-agent": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+      "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+      "dev": true,
+      "requires": {
+        "agent-base": "^4.3.0",
+        "debug": "^3.1.0"
+      },
+      "dependencies": {
+        "agent-base": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+          "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+          "dev": true,
+          "requires": {
+            "es6-promisify": "^5.0.0"
+          }
+        },
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        }
+      }
+    },
     "hugo-bin": {
       "version": "0.120.7",
       "resolved": "https://registry.npmjs.org/hugo-bin/-/hugo-bin-0.120.7.tgz",
         "has-tostringtag": "^1.0.0"
       }
     },
+    "is-running": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz",
+      "integrity": "sha512-mjJd3PujZMl7j+D395WTIO5tU5RIDBfVSRtRR4VOJou3H66E38UjbjvDGh3slJzPuolsb+yQFqwHNNdyp5jg3w==",
+      "dev": true
+    },
     "is-shared-array-buffer": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
         "yargs": "^16.1.1"
       }
     },
+    "karma-browserstack-launcher": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/karma-browserstack-launcher/-/karma-browserstack-launcher-1.6.0.tgz",
+      "integrity": "sha512-Y/UWPdHZkHIVH2To4GWHCTzmrsB6H7PBWy6pw+TWz5sr4HW2mcE+Uj6qWgoVNxvQU1Pfn5LQQzI6EQ65p8QbiQ==",
+      "dev": true,
+      "requires": {
+        "browserstack": "~1.5.1",
+        "browserstack-local": "^1.3.7",
+        "q": "~1.5.0"
+      }
+    },
     "karma-chrome-launcher": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz",
         }
       }
     },
+    "map-stream": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+      "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+      "dev": true
+    },
     "mathml-tag-names": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
       "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
       "dev": true
     },
+    "pause-stream": {
+      "version": "0.0.11",
+      "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+      "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+      "dev": true,
+      "requires": {
+        "through": "~2.3"
+      }
+    },
     "peek-readable": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
       "dev": true
     },
+    "ps-tree": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz",
+      "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==",
+      "dev": true,
+      "requires": {
+        "event-stream": "=3.3.4"
+      }
+    },
     "psl": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
       "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
       "dev": true
     },
+    "stream-combiner": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+      "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+      "dev": true,
+      "requires": {
+        "duplexer": "~0.1.1"
+      }
+    },
     "streamroller": {
       "version": "3.1.5",
       "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz",
         "streamx": "^2.15.0"
       }
     },
+    "temp-fs": {
+      "version": "0.9.9",
+      "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz",
+      "integrity": "sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==",
+      "dev": true,
+      "requires": {
+        "rimraf": "~2.5.2"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "2.5.4",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz",
+          "integrity": "sha512-Lw7SHMjssciQb/rRz7JyPIy9+bbUshEucPoLRvWqy09vC5zQixl8Uet+Zl+SROBB/JMWHJRdCk1qdxNWHNMvlQ==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.0.5"
+          }
+        }
+      }
+    },
     "terser": {
       "version": "5.27.2",
       "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.2.tgz",
index db308449e075c2cfc33b3f43cf8e57cf45e9958c..9544b0783dfac5880dd0789ea1fa706a89e52445 100644 (file)
@@ -71,7 +71,8 @@
     "js-test-karma": "karma start js/tests/karma.conf.js",
     "js-test-integration-bundle": "rollup --config js/tests/integration/rollup.bundle.js",
     "js-test-integration-modularity": "rollup --config js/tests/integration/rollup.bundle-modularity.js",
-    "js-test-cloud": "cross-env LAMBDATEST=true npm-run-all --parallel --race js-test-lt-local js-test-karma",
+    "js-test-cloud": "cross-env BROWSERSTACK=true npm run js-test-karma",
+    "js-test-lt-cloud": "cross-env LAMBDATEST=true npm-run-all --parallel --race js-test-lt-local js-test-karma",
     "js-test-lt-local": "npm-run-all js-test-lt-tunnel sleep",
     "js-test-lt-tunnel": "node js/tests/lt-local",
     "js-test-jquery": "cross-env JQUERY=true npm run js-test-karma",
     "jasmine": "^5.1.0",
     "jquery": "^3.7.1",
     "karma": "^6.4.3",
+    "karma-browserstack-launcher": "^1.6.0",
     "karma-chrome-launcher": "^3.2.0",
     "karma-coverage-istanbul-reporter": "^3.0.3",
     "karma-detect-browsers": "^2.3.3",