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
12 changes: 11 additions & 1 deletion tests/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,19 @@ The e2e test suite includes:
- Testing the beta responses endpoint
- Note: This endpoint is in alpha/beta and may require updates

### Embeddings Tests (`embeddings.test.ts`)
- **Embeddings generation:**
- Generating embeddings for single text input
- Generating embeddings for multiple text inputs (batch processing)
- Verifying consistent embedding dimensions
- Handling edge cases (empty strings)
- Model information validation
- Support for both array and base64 encoded embeddings

## Notes

- Tests make real API calls to OpenRouter, so you need a valid API key
- Tests may consume API credits
- Some tests use the `openai/gpt-3.5-turbo` model by default
- Chat tests use the `meta-llama/llama-3.2-1b-instruct` model by default
- Embeddings tests use the `openai/text-embedding-3-small` model by default
- The beta responses endpoint has limited test coverage as it's still in development
158 changes: 158 additions & 0 deletions tests/e2e/embeddings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { beforeAll, describe, expect, it } from "vitest";
import { OpenRouter } from "../../src/sdk/sdk.js";

describe("Embeddings E2E Tests", () => {
let client: OpenRouter;

beforeAll(() => {
const apiKey = process.env.OPENROUTER_API_KEY;
if (!apiKey) {
throw new Error(
"OPENROUTER_API_KEY environment variable is required for e2e tests"
);
}

client = new OpenRouter({
apiKey,
});
});

describe("embeddings.generate()", () => {
it("should successfully generate embeddings for a single text input", async () => {
const response = await client.embeddings.generate({
input: "The quick brown fox jumps over the lazy dog",
model: "openai/text-embedding-3-small",
});

expect(response).toBeDefined();

// Check if response is an object (not a string)
if (typeof response === "object") {
expect(response.data).toBeDefined();
expect(Array.isArray(response.data)).toBe(true);
expect(response.data.length).toBeGreaterThan(0);

const firstEmbedding = response.data[0];
expect(firstEmbedding).toBeDefined();
expect(firstEmbedding?.embedding).toBeDefined();

// Handle both array and base64 string embeddings
if (Array.isArray(firstEmbedding?.embedding)) {
expect(firstEmbedding.embedding.length).toBeGreaterThan(0);
// Verify embedding values are numbers
const firstValue = firstEmbedding.embedding[0];
expect(typeof firstValue).toBe("number");
} else {
expect(typeof firstEmbedding?.embedding).toBe("string");
}

// Verify usage information if available
if (response.usage) {
expect(response.usage.totalTokens).toBeGreaterThan(0);
}
}
});

it("should generate embeddings for multiple text inputs", async () => {
const inputs = [
"Hello, world!",
"OpenRouter is amazing",
"Embeddings are vector representations of text",
];

const response = await client.embeddings.generate({
input: inputs,
model: "openai/text-embedding-3-small",
});

expect(response).toBeDefined();

if (typeof response === "object") {
expect(response.data).toBeDefined();
expect(Array.isArray(response.data)).toBe(true);
expect(response.data.length).toBe(inputs.length);

// Verify each embedding
response.data.forEach((embedding, index) => {
expect(embedding).toBeDefined();
expect(embedding?.embedding).toBeDefined();

if (Array.isArray(embedding?.embedding)) {
expect(embedding.embedding.length).toBeGreaterThan(0);
} else {
expect(typeof embedding?.embedding).toBe("string");
}

expect(embedding?.index).toBe(index);
});
}
});

it("should generate consistent embedding dimensions", async () => {
const response = await client.embeddings.generate({
input: ["First text", "Second text"],
model: "openai/text-embedding-3-small",
});

expect(response).toBeDefined();

if (typeof response === "object") {
expect(response.data.length).toBe(2);

const firstEmbedding = response.data[0]?.embedding;
const secondEmbedding = response.data[1]?.embedding;

// Only check dimensions if both are arrays
if (Array.isArray(firstEmbedding) && Array.isArray(secondEmbedding)) {
const firstDimension = firstEmbedding.length;
const secondDimension = secondEmbedding.length;

expect(firstDimension).toBe(secondDimension);
expect(firstDimension).toBeGreaterThan(0);
}
}
});

it("should handle empty string input gracefully", async () => {
const response = await client.embeddings.generate({
input: "",
model: "openai/text-embedding-3-small",
});

expect(response).toBeDefined();

if (typeof response === "object") {
expect(response.data).toBeDefined();
expect(Array.isArray(response.data)).toBe(true);

if (response.data.length > 0) {
const embedding = response.data[0];
expect(embedding?.embedding).toBeDefined();
}
}
});

it("should include model information in response", async () => {
const modelName = "openai/text-embedding-3-small";
const response = await client.embeddings.generate({
input: "Test input for model verification",
model: modelName,
});

expect(response).toBeDefined();

if (typeof response === "object") {
expect(response.model).toBeDefined();
expect(typeof response.model).toBe("string");

if (response.usage) {
expect(response.usage.promptTokens).toBeDefined();
expect(response.usage.totalTokens).toBeDefined();
expect(typeof response.usage.promptTokens).toBe("number");
expect(typeof response.usage.totalTokens).toBe("number");
expect(response.usage.totalTokens).toBeGreaterThan(0);
}
}
});
});
});
Loading