ts/e2e-tests/README.md
End-to-end tests for @composio/core and the CLI across different runtimes.
ts/e2e-tests/
├── _utils/ # Shared test infrastructure
│ ├── Dockerfile.node # Docker image for Node.js tests
│ ├── Dockerfile.deno # Docker image for Deno tests
│ ├── Dockerfile.cli # Docker image for CLI tests (scratch)
│ ├── scripts/ # Docker build and cleanup scripts
│ │ ├── docker-build.ts # Pre-build images for all Node/Deno/CLI versions
│ │ └── docker-clean.ts # Remove all e2e Docker images
│ ├── src/ # TypeScript runner utilities
│ │ ├── config.ts # Configuration utilities
│ │ ├── const.ts # Well-known Node.js/Deno versions and timeouts
│ │ ├── e2e.ts # Main e2e test entry point
│ │ ├── image-lifecycle.ts # Docker image build/run utilities
│ │ ├── index.ts # Public exports
│ │ ├── runner.ts # Docker test runner
│ │ ├── sanitize.ts # Output sanitization utilities
│ │ ├── types.ts # TypeScript type definitions
│ │ └── volume.ts # Docker volume management
│ └── README.md # Utils documentation
├── runtimes/
├── node/ # Node.js runtime tests
│ ├── cjs-basic/ # CommonJS compatibility tests
│ ├── custom-tools/ # Custom local tools execution (session.execute, proxyExecute, Zod validation)
│ ├── esm-basic/ # ESM compatibility tests
│ ├── json-schema-to-zod-v3/ # @composio/json-schema-to-zod + Zod v3 tests
│ ├── json-schema-to-zod-v4/ # @composio/json-schema-to-zod + Zod v4 tests
│ ├── mastra-tool-router-zod-v3/ # @composio/mastra Tool Router + Zod v3 tests
│ ├── mastra-tool-router-zod-v4/ # @composio/mastra Tool Router + Zod v4 tests
│ ├── openai-zod4-compat/ # OpenAI + Zod v4 compatibility tests
│ ├── tool-router-files/ # Tool Router session files (list, upload, download, delete)
│ └── typescript-mjs-import-nodenext/ # TypeScript moduleResolution: nodenext tests
├── deno/ # Deno runtime tests
│ └── esm-basic/ # ESM compatibility tests via npm: specifier
└── cloudflare/ # Cloudflare runtime tests
├── cf-workers-basic/ # Basic Cloudflare Workers tests
├── cf-workers-files/ # Cloudflare Workers file handling tests
└── cf-workers-tool-router-ai/ # Cloudflare Workers AI SDK tool router tests
└── cli/ # CLI runtime tests (scratch)
├── version/ # composio version command tests
├── whoami/ # composio whoami command tests
└── toolkits/ # composio toolkits command tests
├── list/ # composio toolkits list tests
├── info/ # composio toolkits info tests
└── search/ # composio toolkits search tests
pnpm test:e2e
pnpm test:e2e:node
Runs Node.js tests in Docker using bun test. The default Node.js version is determined by .nvmrc.
To run with a specific Node.js version:
COMPOSIO_E2E_NODE_VERSION=22.12.0 pnpm test:e2e:node
pnpm test:e2e:deno
Runs Deno tests in Docker using bun test. The default Deno version is determined by .dvmrc.
To run with a specific Deno version:
COMPOSIO_E2E_DENO_VERSION=2.6.7 pnpm test:e2e:deno
pnpm test:e2e:cloudflare
pnpm test:e2e:cli
To run with a specific CLI version:
COMPOSIO_E2E_CLI_VERSION=0.1.24 pnpm test:e2e:cli
runtimes/node/ (e.g., runtimes/node/my-test)package.json with name @e2e-tests/node-my-testtest:e2e and test:e2e:node scriptse2e.test.ts file with inline configuration:import { e2e, type E2ETestResult } from '@e2e-tests/utils';
import { TIMEOUTS } from '@e2e-tests/utils/const';
import { describe, it, expect, beforeAll } from 'bun:test';
e2e(import.meta.url, {
versions: {
node: ['20.18.0', '22.12.0'], // Optional: defaults to .nvmrc version
},
env: { MY_VAR: process.env.MY_VAR }, // Optional: env vars (validated at startup)
defineTests: ({ runtime, runFixture }) => {
let result: E2ETestResult;
beforeAll(async () => {
result = await runFixture({ filename: 'fixtures/test.mjs' });
}, TIMEOUTS.FIXTURE);
describe('output', () => {
it('exits successfully', () => {
expect(result.exitCode).toBe(0);
});
it('contains expected output', () => {
expect(result.stdout).toContain('expected text');
});
});
},
});
fixtures/ directoryruntimes/deno/ (e.g., runtimes/deno/my-test)package.json with name @e2e-tests/deno-my-testtest:e2e and test:e2e:deno scriptse2e.test.ts file with inline configuration:import { e2e, type E2ETestResult } from '@e2e-tests/utils';
import { TIMEOUTS } from '@e2e-tests/utils/const';
import { describe, it, expect, beforeAll } from 'bun:test';
e2e(import.meta.url, {
versions: {
deno: ['2.6.7'], // Optional: defaults to .dvmrc version
},
usesFixtures: true,
defineTests: ({ runtime, runFixture }) => {
let result: E2ETestResult;
beforeAll(async () => {
result = await runFixture({ filename: 'test.ts' });
}, TIMEOUTS.FIXTURE);
describe('output', () => {
it('exits successfully', () => {
expect(result.exitCode).toBe(0);
});
it('contains expected output', () => {
expect(result.stdout).toContain('expected text');
});
});
},
});
fixtures/ directory. Fixtures use Deno's npm: specifier to import packages.For tests that need to install npm packages at runtime, use usesFixtures: true and the setup option:
import { e2e, type E2ETestResultWithSetup } from '@e2e-tests/utils';
import { TIMEOUTS } from '@e2e-tests/utils/const';
import { describe, it, expect, beforeAll } from 'bun:test';
e2e(import.meta.url, {
nodeVersions: ['20.19.0', '22.12.0'],
usesFixtures: true, // Sets cwd to fixtures/ directory
env: { MY_API_KEY: process.env.MY_API_KEY },
defineTests: ({ runFixture }) => {
let result: E2ETestResultWithSetup;
beforeAll(async () => {
result = await runFixture({
filename: 'index.mjs',
setup: 'npm install --legacy-peer-deps', // Runs before fixture
});
}, TIMEOUTS.FIXTURE);
describe('setup', () => {
it('npm install completes successfully', () => {
expect(result.setup.exitCode).toBe(0);
});
});
describe('fixture', () => {
it('exits successfully', () => {
expect(result.exitCode).toBe(0);
});
});
},
});
runtimes/cloudflare/ (e.g., runtimes/cloudflare/my-test)package.json with name @e2e-tests/cf-my-testtest:e2e and test:e2e:cloudflare scripts@cloudflare/vitest-pool-workerscli/ (e.g., cli/my-test)package.json with name @e2e-tests/cli-my-testtest:e2e and test:e2e:cli scriptse2e.test.ts file with inline configuration:import { e2e, sanitizeOutput, type E2ETestResult } from '@e2e-tests/utils';
import { TIMEOUTS } from '@e2e-tests/utils/const';
import { describe, it, expect, beforeAll } from 'bun:test';
e2e(import.meta.url, {
versions: {
cli: ['current'],
},
defineTests: ({ runCmd }) => {
let result: E2ETestResult;
beforeAll(async () => {
result = await runCmd('composio version');
}, TIMEOUTS.FIXTURE);
describe('output', () => {
it('exits successfully', () => {
expect(result.exitCode).toBe(0);
});
it('stdout matches snapshot', () => {
expect(sanitizeOutput(result.stdout)).toMatchSnapshot();
});
});
},
});
Each test suite generates an ephemereal DEBUG.log file in its directory with structured output:
================================================================================
E2E Test: my-test
Started: 2026-01-30T12:18:42.000Z
Test file: ts/e2e-tests/runtimes/node/my-test/e2e.test.ts
Node versions: 20.19.0, 22.12.0
================================================================================
################################################################################
### Node.js 20.19.0
################################################################################
Image: composio-e2e-node:20.19.0
--- Phase 1/2: setup ---
Container: e2e-my-test-20-19-0-1769775520382-setup
Command: npm install
Duration: 2.55s
Exit Code: 0 (success)
[stdout]
added 3 packages in 2s
[stderr]
(empty)
--- Phase 2/2: fixture ---
Container: e2e-my-test-20-19-0-1769775520382-fixture
Command: node index.mjs
Duration: 0.56s
Exit Code: 0 (success)
[stdout]
Test passed!
[stderr]
(empty)
================================================================================
Summary
================================================================================
Node.js 20.19.0: PASS (2 phases, 3.11s total)
Node.js 22.12.0: SKIPPED
Finished: 2026-01-30T12:18:46.500Z
Total duration: 4.50s
================================================================================