Skip to content

Commit 3f0944b

Browse files
committed
feat(tests): 添加多个测试用例以验证功能和错误处理
1 parent ca5ab81 commit 3f0944b

File tree

9 files changed

+169
-17
lines changed

9 files changed

+169
-17
lines changed

.github/workflows/test-and-upload.yml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,8 @@ jobs:
119119
echo "--------------------";
120120
pnpm install;
121121
122-
- name: test packages/core
123-
run: |
124-
cd packages/core;
125-
pnpm run test;
126-
127-
- name: test packages/mitmproxy
128-
run: |
129-
cd packages/mitmproxy;
130-
pnpm run test;
122+
- name: Run all package tests
123+
run: pnpm run test:all
131124

132125
- name: "npm run electron:build"
133126
run: |

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"license": "MPL-2.0",
88
"scripts": {
99
"lint": "eslint .",
10-
"lint:fix": "eslint . --fix"
10+
"lint:fix": "eslint . --fix",
11+
"test:all": "pnpm -C packages/core test && pnpm -C packages/mitmproxy test && pnpm -C packages/cli test && pnpm -C packages/gui test"
1112
},
1213
"devDependencies": {
1314
"@antfu/eslint-config": "^3.16.0",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const assert = require('node:assert')
2+
3+
// Ensure CLI entrypoints load without throwing synchronously
4+
(() => {
5+
assert.doesNotThrow(() => require('../src/index.js'))
6+
assert.doesNotThrow(() => require('../src/mitmproxy.js'))
7+
console.log('cliEntrypointTest passed: CLI modules load')
8+
})()

packages/core/src/shell/scripts/kill-by-port.js

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,51 @@
11
const Shell = require('../shell')
2+
const sudo = require('../sudo')
23

34
const execute = Shell.execute
45

56
const executor = {
67
async windows (exec, { port }) {
7-
const cmds = [`for /f "tokens=5" %a in ('netstat -aon ^| find ":${port}" ^| find "LISTENING"') do (taskkill /f /pid %a & exit /B) `]
8-
await exec(cmds, { type: 'cmd' })
9-
return true
8+
const killCmd = `for /f "tokens=5" %a in ('netstat -aon ^| find ":${port}" ^| find "LISTENING"') do (taskkill /f /pid %a & exit /B)`
9+
try {
10+
await exec([killCmd], { type: 'cmd' })
11+
return true
12+
} catch (e) {
13+
const msg = String(e || '')
14+
if (/Access is denied|not permitted|permission denied/i.test(msg)) {
15+
// Re-run via sudo to trigger UAC elevation on Windows
16+
await sudo(killCmd, { name: `KillByPort ${port}` })
17+
return true
18+
}
19+
throw e
20+
}
1021
},
1122
async linux (exec, { port }) {
12-
await exec(`kill \`lsof -i:${port} |grep 'dev-sidecar\\|electron\\|@docmirro' |awk '{print $2}'\``)
13-
return true
23+
const pidCmd = `lsof -i:${port} |grep 'dev-sidecar\\|electron\\|@docmirro' |awk '{print $2}'`
24+
try {
25+
await exec(`kill \`${pidCmd}\``)
26+
return true
27+
} catch (e) {
28+
const msg = String(e || '')
29+
if (/not permitted|Operation not permitted|permission denied/i.test(msg)) {
30+
await sudo(`kill \`${pidCmd}\``, { name: `KillByPort ${port}` })
31+
return true
32+
}
33+
throw e
34+
}
1435
},
1536
async mac (exec, { port }) {
16-
await exec(`kill \`lsof -i:${port} |grep 'dev-side\\|Elect' |awk '{print $2}'\``)
17-
return true
37+
const pidCmd = `lsof -i:${port} |grep 'dev-side\\|Elect' |awk '{print $2}'`
38+
try {
39+
await exec(`kill \`${pidCmd}\``)
40+
return true
41+
} catch (e) {
42+
const msg = String(e || '')
43+
if (/not permitted|Operation not permitted|permission denied/i.test(msg)) {
44+
await sudo(`kill \`${pidCmd}\``, { name: `KillByPort ${port}` })
45+
return true
46+
}
47+
throw e
48+
}
1849
},
1950
}
2051

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const assert = require('node:assert')
2+
const enableLoopback = require('../src/shell/scripts/enable-loopback')
3+
4+
// lightweight dispatch test: ensures function executes and throws on non-windows
5+
(async () => {
6+
// mock Shell.execute via requiring module uses actual execute; here we just call and expect error on linux/mac
7+
const platform = require('node:os').platform()
8+
try {
9+
await enableLoopback({ port: 0 })
10+
if (platform === 'linux' || platform === 'darwin') {
11+
assert.fail('Expected not supported error on non-windows')
12+
}
13+
console.log('enableLoopback dispatch ok for platform:', platform)
14+
} catch (e) {
15+
if (platform === 'linux' || platform === 'darwin') {
16+
assert.ok(e && //.test(String(e)))
17+
console.log('enableLoopback correctly not supported on', platform)
18+
} else {
19+
// On windows, actual sudo execution would be attempted; we cannot verify here
20+
console.log('enableLoopback attempted on windows')
21+
}
22+
}
23+
})()
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const assert = require('node:assert')
2+
const path = require('node:path')
3+
4+
// Stub Shell.execute and sudo to test fallback without running real commands
5+
const shellModulePath = path.join(__dirname, '../src/shell/index.js')
6+
const sudoModulePath = path.join(__dirname, '../src/shell/sudo.js')
7+
8+
let sudoCalled = false
9+
let sudoCmd = ''
10+
11+
require.cache[shellModulePath] = {
12+
id: shellModulePath,
13+
filename: shellModulePath,
14+
loaded: true,
15+
exports: {
16+
// Simulate linux execution path and a permission error on normal kill
17+
execute: async (executor, _args) => {
18+
const fakeExec = async () => {
19+
const err = new Error('Operation not permitted')
20+
throw err
21+
}
22+
return executor.linux(fakeExec, { port: 12345 })
23+
},
24+
execFile: async () => { }
25+
}
26+
}
27+
28+
require.cache[sudoModulePath] = {
29+
id: sudoModulePath,
30+
filename: sudoModulePath,
31+
loaded: true,
32+
exports: async (command, _options) => {
33+
sudoCalled = true
34+
sudoCmd = command
35+
return { stdout: '', stderr: '' }
36+
}
37+
}
38+
39+
const killByPort = require('../src/shell/scripts/kill-by-port')
40+
41+
(async () => {
42+
await killByPort({ port: 12345 })
43+
assert.ok(sudoCalled, 'Expected sudo fallback to be called')
44+
assert.ok(/lsof -i:12345/.test(sudoCmd), 'Expected sudo command to target the specified port')
45+
console.log('killByPortTest passed: sudo fallback invoked as expected')
46+
})()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const assert = require('node:assert')
2+
3+
// Load bridge modules that are Node-compatible without running Electron
4+
(() => {
5+
assert.doesNotThrow(() => require('../src/bridge/api/open-enable-loopback.js'))
6+
assert.doesNotThrow(() => require('../src/bridge/auto-start/backend.js'))
7+
console.log('bridgeLoadTest passed: bridge modules load without throw')
8+
})()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const assert = require('node:assert')
2+
const path = require('node:path')
3+
4+
// Require the CJS fallback util which is Node-compatible without Electron
5+
const fallbackPath = path.join(__dirname, '../src/utils/os-network-fallback.cjs')
6+
const { installNetworkInterfacesFallback } = require(fallbackPath)
7+
8+
(() => {
9+
let warned = 0
10+
const mockLogger = { warn: () => { warned++ } }
11+
// Calling it should not throw; the function attaches fallback when needed
12+
assert.doesNotThrow(() => installNetworkInterfacesFallback(mockLogger))
13+
assert.ok(typeof installNetworkInterfacesFallback === 'function')
14+
console.log('networkFallbackTest passed: function callable, no throw')
15+
})()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const assert = require('node:assert')
2+
const path = require('node:path')
3+
4+
const Options = require('../src/options')
5+
6+
// This test validates that options compute absolute script/pac paths based on rootDir
7+
(() => {
8+
const rootDir = path.join(__dirname, '../../gui')
9+
const opts = new Options({
10+
setting: {
11+
rootDir,
12+
script: { defaultDir: 'extra/scripts' }
13+
},
14+
plugin: {
15+
overwall: {
16+
pac: { pacFilePath: 'extra/pac/pac.txt' }
17+
}
18+
}
19+
})
20+
21+
const setting = opts.getSetting()
22+
assert.ok(setting.script.dirAbsolutePath.endsWith('/extra/scripts'), 'script dirAbsolutePath should resolve to extra/scripts')
23+
24+
const pacConfig = opts.getPacConfig()
25+
assert.ok(pacConfig.pacFileAbsolutePath.endsWith('/extra/pac/pac.txt'), 'pacFileAbsolutePath should resolve to extra/pac/pac.txt')
26+
console.log('optionsPathTest passed: absolute paths resolved')
27+
})()

0 commit comments

Comments
 (0)