Skip to content

Commit 8f271eb

Browse files
committed
WIP basic tests (yes they are failing)
1 parent 1f4bd0d commit 8f271eb

File tree

5 files changed

+329
-1
lines changed

5 files changed

+329
-1
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@
5555
"scripts": {
5656
"lint": "eslint --cache --max-warnings=0 src",
5757
"build": "tsc",
58-
"prepublishOnly": "npm run build"
58+
"prepublishOnly": "npm run build",
59+
"test": "vitest run",
60+
"test:e2e": "vitest run tests/e2e",
61+
"test:watch": "vitest"
5962
},
6063
"peerDependencies": {
6164
"@tanstack/react-query": "^5",

tests/e2e/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# E2E Tests
2+
3+
This directory contains end-to-end tests for the OpenRouter SDK.
4+
5+
## Prerequisites
6+
7+
1. Install dependencies:
8+
```bash
9+
npm install
10+
```
11+
12+
2. Set up your OpenRouter API key:
13+
```bash
14+
export OPENROUTER_API_KEY=your_api_key_here
15+
```
16+
17+
Or create a `.env` file in the project root:
18+
```
19+
OPENROUTER_API_KEY=your_api_key_here
20+
```
21+
22+
## Running Tests
23+
24+
Run all tests:
25+
```bash
26+
npm test
27+
```
28+
29+
Run only e2e tests:
30+
```bash
31+
npm run test:e2e
32+
```
33+
34+
Run tests in watch mode:
35+
```bash
36+
npm run test:watch
37+
```
38+
39+
## Test Coverage
40+
41+
The e2e test suite includes:
42+
43+
### Models Tests (`models.test.ts`)
44+
- Fetching the list of available models
45+
- Validating model properties
46+
- Filtering models by category
47+
- Getting the total count of models
48+
49+
### Chat Tests (`chat.test.ts`)
50+
- **Non-streaming mode:**
51+
- Sending chat requests and receiving responses
52+
- Multi-turn conversations
53+
- Token limit enforcement
54+
55+
- **Streaming mode:**
56+
- Streaming chat responses
57+
- Progressive content delivery
58+
- Finish reason detection
59+
60+
### Beta Responses Tests (`responses.test.ts`)
61+
- Testing the beta responses endpoint
62+
- Note: This endpoint is in alpha/beta and may require updates
63+
64+
## Notes
65+
66+
- Tests make real API calls to OpenRouter, so you need a valid API key
67+
- Tests may consume API credits
68+
- Some tests use the `openai/gpt-3.5-turbo` model by default
69+
- The beta responses endpoint has limited test coverage as it's still in development

tests/e2e/chat.test.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { beforeAll, describe, expect, it } from "vitest";
2+
import { OpenRouter } from "../../src/sdk/sdk.js";
3+
4+
describe("Chat E2E Tests", () => {
5+
let client: OpenRouter;
6+
7+
beforeAll(() => {
8+
const apiKey = process.env.OPENROUTER_API_KEY;
9+
if (!apiKey) {
10+
throw new Error(
11+
"OPENROUTER_API_KEY environment variable is required for e2e tests"
12+
);
13+
}
14+
15+
client = new OpenRouter({
16+
apiKey,
17+
});
18+
});
19+
20+
describe("chat.send() - Non-streaming", () => {
21+
it("should successfully send a chat request and get a response", async () => {
22+
const response = await client.chat.send({
23+
model: "meta-llama/llama-3.2-1b-instruct",
24+
messages: [
25+
{
26+
role: "user",
27+
content: "Say 'Hello, World!' and nothing else.",
28+
},
29+
],
30+
stream: false,
31+
});
32+
33+
expect(response).toBeDefined();
34+
35+
36+
expect(Array.isArray(response.choices)).toBe(true);
37+
expect(response.choices.length).toBeGreaterThan(0);
38+
39+
const firstChoice = response.choices[0];
40+
expect(firstChoice).toBeDefined();
41+
expect(firstChoice?.message).toBeDefined();
42+
expect(firstChoice?.message?.content).toBeDefined();
43+
expect(typeof firstChoice?.message?.content).toBe("string");
44+
45+
// Verify it has usage information
46+
expect(response.usage).toBeDefined();
47+
expect(response.usage?.totalTokens).toBeGreaterThan(0);
48+
49+
});
50+
51+
it("should handle multi-turn conversations", async () => {
52+
const response = await client.chat.send({
53+
model: "meta-llama/llama-3.2-1b-instruct",
54+
messages: [
55+
{
56+
role: "user",
57+
content: "My name is Alice.",
58+
},
59+
{
60+
role: "assistant",
61+
content: "Hello Alice! How can I help you today?",
62+
},
63+
{
64+
role: "user",
65+
content: "What is my name?",
66+
},
67+
],
68+
stream: false,
69+
});
70+
71+
expect(response).toBeDefined();
72+
73+
const content = typeof response.choices[0]?.message?.content === "string" ? response.choices[0]?.message?.content?.toLowerCase() : response.choices[0]?.message?.content?.map((item) => item.type === "text" ? item.text : "").join("").toLowerCase();
74+
expect(content).toBeDefined();
75+
expect(content).toContain("alice");
76+
77+
});
78+
79+
it("should respect max_tokens parameter", async () => {
80+
const response = await client.chat.send({
81+
model: "meta-llama/llama-3.2-1b-instruct",
82+
messages: [
83+
{
84+
role: "user",
85+
content: "Write a long story about a cat.",
86+
},
87+
],
88+
maxTokens: 10,
89+
stream: false,
90+
});
91+
92+
expect(response).toBeDefined();
93+
94+
expect(response.usage?.completionTokens).toBeLessThanOrEqual(10);
95+
96+
});
97+
});
98+
99+
describe("chat.send() - Streaming", () => {
100+
it("should successfully stream chat responses", async () => {
101+
const response = await client.chat.send({
102+
model: "meta-llama/llama-3.2-1b-instruct",
103+
messages: [
104+
{
105+
role: "user",
106+
content: "Count from 1 to 5.",
107+
},
108+
],
109+
stream: true,
110+
});
111+
112+
expect(response).toBeDefined();
113+
114+
const chunks: any[] = [];
115+
116+
for await (const chunk of response) {
117+
expect(chunk).toBeDefined();
118+
chunks.push(chunk);
119+
}
120+
121+
expect(chunks.length).toBeGreaterThan(0);
122+
123+
// Verify chunks have expected structure
124+
const firstChunk = chunks[0];
125+
expect(firstChunk?.choices).toBeDefined();
126+
expect(Array.isArray(firstChunk?.choices)).toBe(true);
127+
128+
});
129+
130+
it("should stream complete content progressively", async () => {
131+
const response = await client.chat.send({
132+
model: "meta-llama/llama-3.2-1b-instruct",
133+
messages: [
134+
{
135+
role: "user",
136+
content: "Say 'test'.",
137+
},
138+
],
139+
stream: true,
140+
});
141+
142+
expect(response).toBeDefined();
143+
144+
let fullContent = "";
145+
let chunkCount = 0;
146+
147+
for await (const chunk of response) {
148+
chunkCount++;
149+
const delta = chunk.choices?.[0]?.delta;
150+
if (delta?.content) {
151+
fullContent += delta.content;
152+
}
153+
}
154+
155+
expect(chunkCount).toBeGreaterThan(0);
156+
expect(fullContent.length).toBeGreaterThan(0);
157+
}
158+
159+
it("should include finish_reason in final chunk", async () => {
160+
const response = await client.chat.send({
161+
model: "meta-llama/llama-3.2-1b-instruct",
162+
messages: [
163+
{
164+
role: "user",
165+
content: "Say 'done'.",
166+
},
167+
],
168+
stream: true,
169+
});
170+
171+
expect(response).toBeDefined();
172+
173+
let foundFinishReason = false;
174+
175+
for await (const chunk of response) {
176+
const finishReason = chunk.choices?.[0]?.finishReason;
177+
if (finishReason) {
178+
foundFinishReason = true;
179+
expect(typeof finishReason).toBe("string");
180+
}
181+
}
182+
183+
expect(foundFinishReason).toBe(true);
184+
}
185+
});
186+
});

tests/e2e/models.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { beforeAll, describe, expect, it } from "vitest";
2+
import { OpenRouter } from "../../src/sdk/sdk.js";
3+
4+
describe("Models E2E Tests", () => {
5+
let client: OpenRouter;
6+
7+
beforeAll(() => {
8+
const apiKey = process.env.OPENROUTER_API_KEY;
9+
if (!apiKey) {
10+
throw new Error(
11+
"OPENROUTER_API_KEY environment variable is required for e2e tests"
12+
);
13+
}
14+
15+
client = new OpenRouter({
16+
apiKey,
17+
});
18+
});
19+
20+
describe("models.list()", () => {
21+
it("should successfully fetch models list", async () => {
22+
const response = await client.models.list();
23+
24+
expect(response).toBeDefined();
25+
expect(Array.isArray(response)).toBe(true);
26+
expect(response.length).toBeGreaterThan(0);
27+
});
28+
29+
it("should return models with expected properties", async () => {
30+
const response = await client.models.list();
31+
32+
const firstModel = response?.[0];
33+
expect(firstModel).toBeDefined();
34+
expect(firstModel?.id).toBeDefined();
35+
expect(typeof firstModel?.id).toBe("string");
36+
expect(firstModel?.name).toBeDefined();
37+
});
38+
39+
it("should support filtering by category", async () => {
40+
const response = await client.models.list({
41+
category: "text",
42+
});
43+
44+
expect(response).toBeDefined();
45+
expect(Array.isArray(response)).toBe(true);
46+
});
47+
});
48+
49+
describe("models.count()", () => {
50+
it("should successfully fetch models count", async () => {
51+
const response = await client.models.count();
52+
53+
expect(response).toBeDefined();
54+
expect(response.count).toBeDefined();
55+
expect(typeof response.count).toBe("number");
56+
expect(response.count).toBeGreaterThan(0);
57+
});
58+
});
59+
});

vitest.config.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { defineConfig } from "vitest/config";
2+
3+
export default defineConfig({
4+
test: {
5+
globals: true,
6+
environment: "node",
7+
testMatch: ["**/*.test.ts"],
8+
hookTimeout: 30000,
9+
testTimeout: 30000,
10+
},
11+
});

0 commit comments

Comments
 (0)