Skip to content

Commit 76b3a5f

Browse files
authored
Added E2E tests with Bun runtime (#25)
1 parent 1beb2eb commit 76b3a5f

File tree

7 files changed

+152
-3
lines changed

7 files changed

+152
-3
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ jobs:
5454
- name: Build
5555
run: npm run build
5656

57+
- name: Install Bun
58+
uses: oven-sh/setup-bun@v2
59+
5760
- name: E2E tests
5861
# Run without gnome-keyring: @napi-rs/keyring fails fast when no D-Bus secret
5962
# service is available, and keychain.ts automatically falls back to encrypted

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- E2E tests now run under the Bun runtime (in addition to Node.js); use `./test/e2e/run.sh --runtime bun` or `npm run test:e2e:bun`
12+
1013
### Changed
1114
- OS keychain now falls back to `~/.mcpc/credentials.json` (mode 0600) when no keyring daemon is available (e.g. headless Linux servers, containers)
1215

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ After all, UNIX-compatible shell script is THE most universal coding language.
4747

4848
```bash
4949
npm install -g @apify/mcpc
50+
51+
# Or with Bun
52+
bun install -g @apify/mcpc
5053
```
5154

5255
**Linux users:** `mcpc` uses the OS keychain for secure credential storage via the

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@
3232
"build": "tsc",
3333
"build:watch": "tsc --watch",
3434
"build:readme": "./scripts/update-readme.sh",
35-
"test": "npm run build && npm run test:unit && ./test/e2e/run.sh --no-build --parallel 4",
35+
"test": "npm run build && npm run test:unit && ./test/e2e/run.sh --no-build --parallel 4 && ./test/e2e/run.sh --no-build --runtime bun",
3636
"test:unit": "jest",
3737
"test:watch": "jest --watch",
3838
"test:coverage": "npm run test:coverage:unit && npm run test:coverage:e2e && npm run test:coverage:merge",
3939
"test:coverage:unit": "jest --coverage && find test/coverage/unit -name '*.html' -exec sed -i '' -e 's/Code coverage report for All files/mcpc Coverage (Unit Tests)/g' -e 's/<h1>All files<\\/h1>/<h1>Unit Test Coverage<\\/h1>/g' {} \\;",
4040
"test:coverage:e2e": "./test/e2e/run.sh --coverage",
4141
"test:coverage:merge": "test/coverage/coverage-merge.sh",
4242
"test:e2e": "./test/e2e/run.sh --keep",
43+
"test:e2e:bun": "./test/e2e/run.sh --no-build --runtime bun",
4344
"lint": "eslint src/**/*.ts && prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
4445
"lint:fix": "eslint src/**/*.ts --fix && prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
4546
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",

test/e2e/lib/framework.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ _cleanup_keychain() {
179179
# ============================================================================
180180

181181
# Path to mcpc
182-
MCPC="node $PROJECT_ROOT/dist/cli/index.js"
182+
# Runtime can be overridden via E2E_RUNTIME env var (e.g. E2E_RUNTIME=bun)
183+
MCPC="${E2E_RUNTIME:-node} $PROJECT_ROOT/dist/cli/index.js"
183184

184185
# Run mcpc and capture output
185186
# Sets: STDOUT, STDERR, EXIT_CODE

test/e2e/run.sh

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ KEEP_RUNS=false
2929
VERBOSE=false
3030
LIST_ONLY=false
3131
SKIP_BUILD=false
32+
RUNTIME="node"
3233
PATTERNS=()
3334

3435
# Colors
@@ -66,6 +67,10 @@ while [[ $# -gt 0 ]]; do
6667
LIST_ONLY=true
6768
shift
6869
;;
70+
-r|--runtime)
71+
RUNTIME="$2"
72+
shift 2
73+
;;
6974
-b|--no-build)
7075
SKIP_BUILD=true
7176
shift
@@ -75,6 +80,7 @@ while [[ $# -gt 0 ]]; do
7580
echo ""
7681
echo "Options:"
7782
echo " -p, --parallel N Max parallel tests (default: 16)"
83+
echo " -r, --runtime <r> Runtime for mcpc: node (default) or bun"
7884
echo " -i, --isolated Force all tests to use isolated home directories"
7985
echo " -c, --coverage Collect code coverage"
8086
echo " -b, --no-build Skip building mcpc (assumes dist/ is up to date)"
@@ -163,6 +169,25 @@ if [[ ${#TESTS[@]} -eq 0 ]]; then
163169
exit 1
164170
fi
165171

172+
# Validate runtime and resolve version string
173+
case "$RUNTIME" in
174+
node)
175+
RUNTIME_VERSION="node $(node --version)"
176+
;;
177+
bun)
178+
if ! command -v bun &>/dev/null; then
179+
echo "bun is not installed; skipping bun runtime tests"
180+
exit 0
181+
fi
182+
RUNTIME_VERSION="bun $(bun --version)"
183+
;;
184+
*)
185+
echo "Unknown runtime: $RUNTIME (valid options: node, bun)" >&2
186+
exit 1
187+
;;
188+
esac
189+
export E2E_RUNTIME="$RUNTIME"
190+
166191
# List mode
167192
if [[ "$LIST_ONLY" == "true" ]]; then
168193
echo "Available tests:"
@@ -190,6 +215,7 @@ echo "Run ID: $E2E_RUN_ID"
190215
echo "Run dir: $RUN_DIR"
191216
echo "Tests: ${#TESTS[@]}"
192217
echo "Parallel: $PARALLEL"
218+
echo "Runtime: $RUNTIME_VERSION"
193219
if [[ "$ISOLATED_ALL" == "true" ]]; then
194220
echo "Home dirs: isolated (per-test)"
195221
else
@@ -252,7 +278,7 @@ run_test() {
252278
}
253279

254280
export -f run_test test_name
255-
export SCRIPT_DIR SUITES_DIR E2E_RUN_ID E2E_RUNS_DIR E2E_SHARED_HOME E2E_ISOLATED_ALL PROJECT_ROOT NODE_V8_COVERAGE
281+
export SCRIPT_DIR SUITES_DIR E2E_RUN_ID E2E_RUNS_DIR E2E_SHARED_HOME E2E_ISOLATED_ALL E2E_RUNTIME PROJECT_ROOT NODE_V8_COVERAGE
256282

257283
# Run tests
258284
echo -e "${BLUE}Running tests...${NC}"

test/e2e/suites/basic/bun.test.sh

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/bin/bash
2+
# Test: mcpc works under the Bun runtime
3+
# Skipped automatically if bun is not installed.
4+
#
5+
# When run standalone this sets MCPC to use bun directly.
6+
# When run via `./run.sh --runtime bun`, E2E_RUNTIME=bun is already set by the
7+
# runner and framework.sh picks it up; the explicit override below is a no-op.
8+
9+
source "$(dirname "$0")/../../lib/framework.sh"
10+
test_init "basic/bun"
11+
12+
# Skip entire test suite if bun is not available
13+
if ! command -v bun &>/dev/null; then
14+
echo "# Bun not installed, skipping"
15+
test_case "bun runtime (skipped - bun not installed)"
16+
test_skip "bun not installed"
17+
test_done
18+
fi
19+
20+
BUN_VERSION=$(bun --version)
21+
echo "# Bun version: $BUN_VERSION"
22+
23+
# Ensure all mcpc invocations in this file use bun (for standalone runs)
24+
MCPC="bun $PROJECT_ROOT/dist/cli/index.js"
25+
26+
# Start test server (still uses Node/tsx - it's the remote MCP server, not the client)
27+
start_test_server
28+
29+
# Test: --version works under Bun
30+
test_case "bun: --version works"
31+
run_mcpc --version
32+
assert_success
33+
if [[ ! "$STDOUT" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
34+
test_fail "version should be semver format, got: $STDOUT"
35+
exit 1
36+
fi
37+
test_pass
38+
39+
# Test: --help works under Bun
40+
test_case "bun: --help works"
41+
run_mcpc --help
42+
assert_success
43+
assert_contains "$STDOUT" "Usage:"
44+
assert_contains "$STDOUT" "mcpc"
45+
test_pass
46+
47+
# Test: --json output works under Bun
48+
test_case "bun: --version --json works"
49+
run_mcpc --version --json
50+
assert_success
51+
assert_json_valid "$STDOUT"
52+
assert_json "$STDOUT" '.version'
53+
test_pass
54+
55+
# Test: tools-list via direct connection
56+
test_case "bun: tools-list (direct connection)"
57+
run_xmcpc "$TEST_SERVER_URL" tools-list
58+
assert_success
59+
assert_contains "$STDOUT" "echo"
60+
test_pass
61+
62+
# Test: tools-call via direct connection
63+
test_case "bun: tools-call (direct connection)"
64+
run_mcpc "$TEST_SERVER_URL" tools-call echo 'message:=hello from bun'
65+
assert_success
66+
assert_contains "$STDOUT" "hello from bun"
67+
test_pass
68+
69+
# Test: resources-list via direct connection
70+
test_case "bun: resources-list (direct connection)"
71+
run_xmcpc "$TEST_SERVER_URL" resources-list
72+
assert_success
73+
test_pass
74+
75+
# Test: JSON mode via direct connection
76+
test_case "bun: tools-list --json (direct connection)"
77+
run_mcpc --json "$TEST_SERVER_URL" tools-list
78+
assert_success
79+
assert_json_valid "$STDOUT"
80+
test_pass
81+
82+
# =============================================================================
83+
# Keychain path: create a session with a bearer token.
84+
# mcpc stores the token in the OS keychain (via @napi-rs/keyring) on connect,
85+
# then reads it back on every subsequent command. This exercises the native
86+
# keyring add-on under the Bun runtime.
87+
# =============================================================================
88+
89+
test_case "bun: session with bearer token (keychain write)"
90+
SESSION=$(session_name "bearer")
91+
run_mcpc "$TEST_SERVER_URL" --header "Authorization: Bearer testtoken-bun-$$" connect "$SESSION"
92+
assert_success
93+
test_pass
94+
95+
test_case "bun: session tools-list (keychain read)"
96+
run_xmcpc "$SESSION" tools-list
97+
assert_success
98+
assert_contains "$STDOUT" "echo"
99+
test_pass
100+
101+
test_case "bun: session tools-call (keychain read)"
102+
run_mcpc "$SESSION" tools-call echo 'message:=hello from bun session'
103+
assert_success
104+
assert_contains "$STDOUT" "hello from bun session"
105+
test_pass
106+
107+
test_case "bun: session close"
108+
run_mcpc "$SESSION" close
109+
assert_success
110+
test_pass
111+
112+
test_done

0 commit comments

Comments
 (0)