|
| 1 | +// Script which checks all browsers in test/integration/browser.js against supported BrowserStack browsers |
| 2 | +// Meant to be run manually, by running `yarn test:integration:checkbrowsers` from the command line |
| 3 | + |
| 4 | +const btoa = require('btoa'); |
| 5 | +const fetch = require('node-fetch'); |
| 6 | +const localConfigs = require('../test/integration/browsers.js'); |
| 7 | + |
| 8 | +const browserstackUsername = process.env.BROWSERSTACK_USERNAME; |
| 9 | +const browserstackAccessKey = process.env.BROWSERSTACK_ACCESS_KEY; |
| 10 | + |
| 11 | +const hasCreds = () => { |
| 12 | + return browserstackUsername !== undefined && browserstackAccessKey !== undefined; |
| 13 | +}; |
| 14 | + |
| 15 | +const fetchCurrentData = (username, key) => { |
| 16 | + const authKey = btoa(`${username}:${key}`); |
| 17 | + |
| 18 | + return fetch('https://api.browserstack.com/5/browsers?flat=true', { |
| 19 | + headers: { |
| 20 | + Authorization: `Basic ${authKey}`, |
| 21 | + }, |
| 22 | + }).then(response => { |
| 23 | + if (response.status >= 200 && response.status < 300) { |
| 24 | + return response.json(); |
| 25 | + } else { |
| 26 | + throw new Error(`Unable to fetch data. Status: ${response.status} ${response.statusText}`); |
| 27 | + } |
| 28 | + }); |
| 29 | +}; |
| 30 | + |
| 31 | +const isMatchingEntry = (key, localConfig, bsConfig) => { |
| 32 | + let localValue = localConfig[key]; |
| 33 | + let bsValue = bsConfig[key]; |
| 34 | + |
| 35 | + // all values are either null, undefined, or strings, so checking truthiness should |
| 36 | + // save us from trying to lowercase anything that can't handle it |
| 37 | + if (localValue) { |
| 38 | + localValue = localValue.toLowerCase(); |
| 39 | + } |
| 40 | + if (bsValue) { |
| 41 | + bsValue = bsValue.toLowerCase(); |
| 42 | + } |
| 43 | + |
| 44 | + if (localValue === bsValue) { |
| 45 | + return true; |
| 46 | + } |
| 47 | + if (key === 'browser_version' && localValue === 'latest') { |
| 48 | + return true; |
| 49 | + } |
| 50 | + |
| 51 | + return false; |
| 52 | +}; |
| 53 | + |
| 54 | +const isMatchingConfig = (localConfig, bsConfig) => { |
| 55 | + const checkKeys = ['os', 'os_version', 'browser', 'device', 'browser_version']; |
| 56 | + |
| 57 | + // bail on the first non-matching entry |
| 58 | + if (checkKeys.some(key => !isMatchingEntry(key, localConfig, bsConfig))) { |
| 59 | + return false; |
| 60 | + } |
| 61 | + |
| 62 | + // while we're here, if we've found a match on everything else, make sure |
| 63 | + // real_mobile is up to date. Now the data *really* matches! |
| 64 | + if (localConfig.real_mobile !== bsConfig.real_mobile) { |
| 65 | + localConfig.real_mobile_updated = true; // flag for later |
| 66 | + localConfig.real_mobile = bsConfig.real_mobile; |
| 67 | + } |
| 68 | + |
| 69 | + return true; |
| 70 | +}; |
| 71 | + |
| 72 | +const isSupported = (localConfig, supportedConfigs) => { |
| 73 | + return supportedConfigs.some(supportedConfig => isMatchingConfig(localConfig, supportedConfig)); |
| 74 | +}; |
| 75 | + |
| 76 | +const checkLocalConfigsVsBrowserStack = (localConfigs, bsConfigs) => { |
| 77 | + const unsupportedConfigs = []; |
| 78 | + const realMobileUpdates = []; |
| 79 | + |
| 80 | + // check each local config against the entire collection of BS configs |
| 81 | + for (const configName in localConfigs) { |
| 82 | + const localConfig = localConfigs[configName]; |
| 83 | + |
| 84 | + console.log(`\nChecking ${configName}`); |
| 85 | + |
| 86 | + if (!isSupported(localConfig, bsConfigs)) { |
| 87 | + console.log(' UNSUPPORTED'); |
| 88 | + unsupportedConfigs.push(configName); |
| 89 | + } else if (localConfig.real_mobile_updated) { |
| 90 | + console.log(' Supported (but needs real_mobile update)'); |
| 91 | + realMobileUpdates.push(configName); |
| 92 | + } else { |
| 93 | + console.log(' Supported!'); |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + // report on unsupported configs |
| 98 | + if (unsupportedConfigs.length) { |
| 99 | + console.log('\nFound unsupported browser configurations:'); |
| 100 | + for (const configName of unsupportedConfigs) { |
| 101 | + console.log(`\n${configName}: `, localConfigs[configName]); |
| 102 | + } |
| 103 | + console.log( |
| 104 | + '\nPlease visit https://api.browserstack.com/5/browsers or https://api.browserstack.com/5/browsers?flat=true to choose new configurations.', |
| 105 | + ); |
| 106 | + } else { |
| 107 | + console.log('\nAll configurations supported!\n'); |
| 108 | + } |
| 109 | + |
| 110 | + // report on real_mobile updates |
| 111 | + if (realMobileUpdates.length) { |
| 112 | + console.log('\nFound supported browser configurations which need real_mobile updated:\n'); |
| 113 | + for (const configName of realMobileUpdates) { |
| 114 | + console.log(configName, 'new real_mobile value: ', localConfigs[configName].real_mobile); |
| 115 | + } |
| 116 | + } |
| 117 | +}; |
| 118 | + |
| 119 | +const findUnsupportedConfigs = localConfigs => { |
| 120 | + if (!hasCreds()) { |
| 121 | + console.warn( |
| 122 | + 'Unable to find API credentials in env. Please export them as BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY.', |
| 123 | + ); |
| 124 | + return; |
| 125 | + } |
| 126 | + |
| 127 | + fetchCurrentData(browserstackUsername, browserstackAccessKey) |
| 128 | + .then(data => checkLocalConfigsVsBrowserStack(localConfigs, data)) |
| 129 | + .catch(err => console.log(err)); |
| 130 | +}; |
| 131 | + |
| 132 | +findUnsupportedConfigs(localConfigs); |
0 commit comments