Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 44 additions & 8 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,33 @@ on:
workflow_call:

jobs:
lint_and_test:
name: Lint & Test
lint:
name: Lint
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
runs-on: ubuntu-24.04

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Use Node.js 24
uses: actions/setup-node@v6
with:
node-version: 24

- name: Install Dependencies
run: npm install

- name: Lint code
run: npm run lint

unit:
name: Unit tests (Node.js ${{ matrix.node-version }})
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
runs-on: ubuntu-24.04

strategy:
fail-fast: false
matrix:
node-version: [20, 22, 24]

Expand All @@ -28,13 +49,28 @@ jobs:
- name: Install Dependencies
run: npm install

# Lint only on the latest Node.js version to save time.
- name: Lint code
if: ${{ matrix.node-version == 24 }}
run: npm run lint
- name: Run unit tests
run: npm run test:unit
Comment on lines 30 to +53
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This job still contains lint, it should either be reflected in the name or separated into another job

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call — extracted lint into its own dedicated Lint job alongside Unit tests and E2E tests in 31d794d.


Generated by Claude Code


e2e:
name: E2E tests
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
runs-on: ubuntu-24.04

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Use Node.js 24
uses: actions/setup-node@v6
with:
node-version: 24

- name: Install Dependencies
run: npm install

- name: Add localhost-test to Linux hosts file
run: sudo echo "127.0.0.1 localhost-test" | sudo tee -a /etc/hosts

- name: Run Tests
run: npm test
- name: Run E2E tests
run: npm run test:e2e
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
"clean": "rimraf dist",
"prepublishOnly": "npm run build",
"local-proxy": "tsx test/utils/run_locally.js",
"test": "nyc cross-env NODE_OPTIONS=--insecure-http-parser mocha",
"test": "nyc cross-env NODE_OPTIONS=--insecure-http-parser mocha 'test/unit/**/*.js' 'test/e2e/**/*.js'",
"test:unit": "mocha 'test/unit/**/*.js'",
"test:e2e": "nyc cross-env NODE_OPTIONS=--insecure-http-parser mocha 'test/e2e/**/*.js'",
"test:docker": "docker build --tag proxy-chain-tests --file test/Dockerfile . && docker run --add-host localhost-test:127.0.0.1 proxy-chain-tests",
"test:docker:all": "bash scripts/test-docker-all.sh",
"lint": "eslint .",
Expand Down
36 changes: 29 additions & 7 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Tests

The test suite is split into two directories:

- `test/unit/` — pure unit tests over utility helpers (no network, no proxy
servers). Fast; runs in CI on every supported major Node.js version.
- `test/e2e/` — end-to-end tests that spin up real HTTP/HTTPS/SOCKS proxy
servers and target servers. Heavier; runs in CI on the latest Node.js
only.

Shared helpers live in `test/utils/`.

## Docker (recommended)

Since Linux and macOS handle sockets differently, please run tests in a Docker container
Expand All @@ -14,13 +24,13 @@ to have a consistent Linux environment for running tests.
2. Run a specific test file

```bash
npm run test:docker test/server.js
npm run test:docker test/e2e/server.js
```

3. Run all `direct ipv6` test cases across all tests

```bash
npm run test:docker test/server.js -- --grep "direct ipv6"
npm run test:docker test/e2e/server.js -- --grep "direct ipv6"
```

Note: for test in Docker no changes in `/etc/hosts` needed.
Expand All @@ -29,7 +39,7 @@ Note: for test in Docker no changes in `/etc/hosts` needed.

### Prerequisites

1. Node.js 18+ (see `.nvmrc` for exact version)
1. Node.js 20+ (see `.nvmrc` for exact version)
2. For MacOS with ARM CPUs install Rosetta (workaround for puppeteer)
3. Update `/etc/hosts`

Expand All @@ -47,14 +57,26 @@ Note: for test in Docker no changes in `/etc/hosts` needed.

### Run tests

1. Run all tests
1. Run all tests (unit + e2e)

```bash
npm run test
npm test
```

2. Run a specific test file
2. Run only unit tests

```bash
npm run test:unit
```

3. Run only e2e tests

```bash
npm run test:e2e
```

4. Run a specific test file

```bash
npm run test test/anonymize_proxy.js
npm test test/e2e/anonymize_proxy.js
```
4 changes: 2 additions & 2 deletions test/anonymize_proxy.js → test/e2e/anonymize_proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import basicAuthParser from 'basic-auth-parser';
import request from 'request';
import express from 'express';

import { anonymizeProxy, closeAnonymizedProxy, listenConnectAnonymizedProxy } from '../src/index.js';
import { expectThrowsAsync } from './utils/throws_async.js';
import { anonymizeProxy, closeAnonymizedProxy, listenConnectAnonymizedProxy } from '../../src/index.js';
import { expectThrowsAsync } from '../utils/throws_async.js';

let expressServer;
let proxyServer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import basicAuthParser from 'basic-auth-parser';
import request from 'request';
import express from 'express';

import { anonymizeProxy, closeAnonymizedProxy } from '../src/index.js';
import { anonymizeProxy, closeAnonymizedProxy } from '../../src/index.js';

let expressServer;
let proxyServer;
Expand Down
2 changes: 1 addition & 1 deletion test/ee-memory-leak.js → test/e2e/ee-memory-leak.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import net from 'node:net';
import http from 'node:http';
import { assert } from 'chai';
import * as ProxyChain from '../src/index.js';
import * as ProxyChain from '../../src/index.js';

describe('ProxyChain server', () => {
let server;
Expand Down
4 changes: 2 additions & 2 deletions test/http-agent.js → test/e2e/http-agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import portastic from 'portastic';
import proxy from 'proxy';
import request from 'request';

import { Server } from '../src/index.js';
import { TargetServer } from './utils/target_server.js';
import { Server } from '../../src/index.js';
import { TargetServer } from '../utils/target_server.js';

const sslKey = fs.readFileSync(path.join(import.meta.dirname, 'ssl.key'));
const sslCrt = fs.readFileSync(path.join(import.meta.dirname, 'ssl.crt'));
Expand Down
2 changes: 1 addition & 1 deletion test/https-server.js → test/e2e/https-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import path from 'node:path';
import tls from 'node:tls';
import { expect } from 'chai';
import http from 'node:http';
import { Server } from '../src/index.js';
import { Server } from '../../src/index.js';

const sslKey = fs.readFileSync(path.join(import.meta.dirname, 'ssl.key'));
const sslCrt = fs.readFileSync(path.join(import.meta.dirname, 'ssl.crt'));
Expand Down
4 changes: 2 additions & 2 deletions test/https-stress-test.js → test/e2e/https-stress-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import tls from 'node:tls';
import util from 'node:util';
import request from 'request';
import { expect } from 'chai';
import { Server } from '../src/index.js';
import { TargetServer } from './utils/target_server.js';
import { Server } from '../../src/index.js';
import { TargetServer } from '../utils/target_server.js';

// Node.js 20+ enables HTTP keep-alive by default in the global agent,
// which causes connection tracking issues in tests. Disable it.
Expand Down
6 changes: 3 additions & 3 deletions test/server.js → test/e2e/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import request from 'request';
import WebSocket from 'faye-websocket';
import { gotScraping } from 'got-scraping';

import { parseAuthorizationHeader } from '../src/utils/parse_authorization_header.js';
import { Server, RequestError } from '../src/index.js';
import { TargetServer } from './utils/target_server.js';
import { parseAuthorizationHeader } from '../../src/utils/parse_authorization_header.js';
import { Server, RequestError } from '../../src/index.js';
import { TargetServer } from '../utils/target_server.js';

/*
TODO - add following tests:
Expand Down
2 changes: 1 addition & 1 deletion test/socks.js → test/e2e/socks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import portastic from 'portastic';
import socksv5 from 'socksv5';
import { gotScraping } from 'got-scraping';
import { expect } from 'chai';
import * as ProxyChain from '../src/index.js';
import * as ProxyChain from '../../src/index.js';

describe('SOCKS protocol', () => {
let socksServer;
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions test/tcp_tunnel.js → test/e2e/tcp_tunnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { expect, assert } from 'chai';
import http from 'node:http';
import proxy from 'proxy';

import { createTunnel, closeTunnel } from '../src/index.js';
import { expectThrowsAsync } from './utils/throws_async.js';
import { createTunnel, closeTunnel } from '../../src/index.js';
import { expectThrowsAsync } from '../utils/throws_async.js';

const destroySocket = (socket) => new Promise((resolve) => {
if (!socket || socket.destroyed) return resolve();
Expand Down
6 changes: 3 additions & 3 deletions test/tools.js → test/unit/tools.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from 'chai';
import { redactUrl } from '../src/utils/redact_url.js';
import { isHopByHopHeader } from '../src/utils/is_hop_by_hop_header.js';
import { parseAuthorizationHeader } from '../src/utils/parse_authorization_header.js';
import { redactUrl } from '../../src/utils/redact_url.js';
import { isHopByHopHeader } from '../../src/utils/is_hop_by_hop_header.js';
import { parseAuthorizationHeader } from '../../src/utils/parse_authorization_header.js';

describe('tools.redactUrl()', () => {
it('works', () => {
Expand Down
Loading