Skip to content

Commit

Permalink
feat: setup OS proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
tianfeng92 committed Oct 21, 2023
1 parent aaf4bab commit e5cb586
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 111 deletions.
239 changes: 130 additions & 109 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
"dependencies": {
"@saucelabs/testcomposer": "^2.0.0",
"@tsconfig/node20": "20.1.2",
"@types/shelljs": "^0.8.14",
"dotenv": "16.3.1",
"lodash": "^4.17.21",
"mocha-junit-reporter": "^2.2.1",
"sauce-testrunner-utils": "2.0.0",
"shelljs": "^0.8.5",
"testcafe": "3.3.0",
"testcafe-browser-provider-ios": "0.5.0",
"testcafe-reporter-saucelabs": "3.1.0",
Expand Down
2 changes: 2 additions & 0 deletions scripts/bundle.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
set -e
rm -rf ./bundle/
mkdir ./bundle/
mkdir -p ./bundle/scripts
cp -r ./src/ ./bundle/src/
cp -r ./bin/ bundle/bin/
cp package.json bundle/package.json
cp package-lock.json bundle/package-lock.json
cp tsconfig.json bundle/tsconfig.json
cp "$(which node)" bundle/
cp ./scripts/win-refresh-wininet.ps1 bundle/scripts/win-refresh-wininet.ps1

pushd bundle/
npm cache clean --force
Expand Down
16 changes: 16 additions & 0 deletions scripts/win-refresh-wininet.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# adapted from https://gist.github.com/mikeperri/36e656f28e42aa9cee18ce88361f6c16
# refreshes wininet so it is aware of new registry changes

$signature = @'
[DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
'@

$INTERNET_OPTION_SETTINGS_CHANGED = 39
$INTERNET_OPTION_REFRESH = 37

$type = Add-Type -MemberDefinition $signature -Name wininet -Namespace pinvoke -PassThru
$a = $type::InternetSetOption(0, $INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)
$b = $type::InternetSetOption(0, $INTERNET_OPTION_REFRESH, 0, 0)

$a -and $b
88 changes: 88 additions & 0 deletions src/network-proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import * as shell from "shelljs";
import path from 'path';

const networkSetup = '/usr/sbin/networksetup';

export function isProxyAvaliable() {
const proxy = process.env.HTTP_PROXY;
return proxy && Array.isArray(proxy.split(':')) && proxy.split(':').length > 2;
}

function getProxySetting() {
const proxy = process.env.HTTP_PROXY?.split(':') || [];
if (proxy?.length < 2) {
return;
}
return {
proxyHost: proxy[1].replaceAll('/', ''),
proxyPort: proxy[2],
}
}

function findNetworkServiceOnMac() {
const networkInfo = shell.exec(`${networkSetup} -listnetworkserviceorder`, {async: false}).stdout;
const lines = networkInfo.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes('Device: en')) {
// Network service name would be shown like: (1) Wi-Fi.
// Extract "Wi-Fi" from this line.
const service = lines[i-1].substring(4);
const serviceInfo = shell.exec(`${networkSetup} -getinfo "${service}"`, {async: false}).stdout;
for (const l of serviceInfo.split('\n')) {
if (l.includes('IP address') && !l.includes('IPv6') && !l.includes('none')) {
return service;
}
}
}
}
return 'Ethernet';
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setupMacProxy(proxy: any) {
const {
proxyHost,
proxyPort,
} = proxy;
const networkService = findNetworkServiceOnMac();
shell.exec(`sudo ${networkSetup} -setwebproxy "${networkService}" ${proxyHost} ${proxyPort}`, {async: false});
shell.exec(`sudo ${networkSetup} -setsecurewebproxy "${networkService}" ${proxyHost} ${proxyPort}`, {async: false});
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setupWinProxy(proxy: any) {
const {
proxyHost,
proxyPort,
} = proxy;
const prefix =
'reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" /v ';
const opts = { async: false};
shell.exec(`${prefix} MigrateProxy /t REG_DWORD /d 1 /f`, opts)
shell.exec(`${prefix} ProxyEnable /t REG_DWORD /d 1 /f`, opts)
shell.exec(`${prefix} ProxyHttp1.1 /t REG_DWORD /d 1 /f`, opts)
shell.exec(`${prefix} EnableLegacyAutoProxyFeatures /t REG_DWORD /d 1 /f`, opts)
shell.exec(`${prefix} ProxyServer /t REG_SZ /d "${proxyHost}:${proxyPort}" /f`, opts)
shell.exec(`${prefix} ProxyOverride /t REG_SZ /d "localhost;127.0.0.1" /f`, opts)

// Registry changes won't take effect immediately; we need to refresh wininet.
const refreshScript = path.join(__dirname, '../', 'scripts', 'win-refresh-wininet.ps1');
shell.exec(`powershell.exe -ExecutionPolicy Bypass ${refreshScript}`, opts);
}

export function setupProxy() {
const proxy = getProxySetting();
if (!proxy) {
return;
}
console.log(`Setting system proxy settings: ${proxy.proxyHost}:${proxy.proxyPort}`);
switch (process.platform) {
case 'darwin':
setupMacProxy(proxy);
break;
case 'win32':
setupWinProxy(proxy);
break;
}
}
17 changes: 15 additions & 2 deletions src/testcafe-runner.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {spawn} from 'child_process';
import path from 'path';
import fs from 'fs';
import {TestCafeConfig, Suite, CompilerOptions, second} from './type';

import {
getArgs,
loadRunConfig,
Expand All @@ -11,9 +9,15 @@ import {
prepareNpmEnv,
preExec,
} from 'sauce-testrunner-utils';

import {TestCafeConfig, Suite, CompilerOptions, second} from './type';
import {
generateJunitFile
} from './sauce-testreporter';
import {
setupProxy,
isProxyAvaliable,
} from './network-proxy';

async function prepareConfiguration(nodeBin: string, runCfgPath: string, suiteName: string) {
runCfgPath = getAbsolutePath(runCfgPath);
Expand Down Expand Up @@ -225,6 +229,11 @@ export function buildCommandLine(suite: Suite | undefined, projectPath: string,
return cli;
}

function isCDPDisabled() {
const cfg = require(path.join(__dirname, 'sauce-testcafe-config.cjs'))
return cfg.disableNativeAutomation;
}

async function runTestCafe(tcCommandLine: (string | number)[], projectPath: string, timeout: second) {
const nodeBin = process.argv[0];
const testcafeBin = path.join(__dirname, '..', 'node_modules', 'testcafe', 'lib', 'cli');
Expand Down Expand Up @@ -266,6 +275,10 @@ async function run(nodeBin: string, runCfgPath: string, suiteName: string) {
suite
} = await prepareConfiguration(nodeBin, runCfgPath, suiteName);

if (suite.browserName === 'chrome' && !isCDPDisabled() && isProxyAvaliable()) {
setupProxy();
}

if (!await preExec.run({preExec: suite.preExec}, preExecTimeout)) {
return false;
}
Expand Down

0 comments on commit e5cb586

Please sign in to comment.