Skip to content
Open
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
11 changes: 9 additions & 2 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
"lint:fix": "bun run lint --fix",
"preview": "next build && next start",
"start": "bun --env-file=../../.env run next start",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest",
"test:e2e": "vitest run test/e2e"
},
"dependencies": {
"@agentset/db": "workspace:*",
Expand Down Expand Up @@ -73,11 +76,15 @@
"@types/node": "^22.10.10",
"@types/react": "catalog:react19",
"@types/react-dom": "catalog:react19",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/ui": "^3.2.4",
"dotenv": "^17.2.3",
"eslint": "catalog:",
"postcss": "^8.4.39",
"prettier": "catalog:",
"tailwindcss": "catalog:",
"typescript": "catalog:"
"typescript": "catalog:",
"vitest": "catalog:"
},
"prettier": "@agentset/prettier-config"
}
6 changes: 6 additions & 0 deletions apps/web/test/.env.test.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copy this file to .env.test.local and fill in your values
# .env.test.local is gitignored and won't be committed

TEST_API_KEY=your_test_api_key_here
TEST_BASE_URL=http://localhost:3000
TEST_NAMESPACE_ID=your_namespace_id_here
53 changes: 53 additions & 0 deletions apps/web/test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# E2E Tests

End-to-end tests for the Agentset public API endpoints.

## Prerequisites

1. **Server must be running** on `localhost:3000`:
```bash
bun run dev
```

2. **Set up environment variables**:
```bash
# Copy the example file
cp .env.test.example .env.test.local

# Edit with your values
```

Required variables:
- `TEST_API_KEY` - Your Agentset API key (create from dashboard)
- `TEST_BASE_URL` - Server URL (default: `http://localhost:3000`)
- `TEST_NAMESPACE_ID` - A namespace ID to test against

## Running Tests

Run all commands from the `apps/web` directory:

```bash
cd apps/web

# Run all E2E tests
bun run test:e2e

# Run all tests (including unit tests if any)
bun run test

# Watch mode for development
bun run test:watch
```

## Test Coverage

### Endpoints Tested
- **Health** - `GET /api/health`
- **Namespace API** - `GET /api/v1/namespace`
- **Ingest Jobs API** - `POST` and `GET` operations

### Test Types
- Happy path (successful responses)
- Authentication errors (401 - missing/invalid API key)
- Validation errors (400/422 - invalid payloads)
- Not found errors (404 - non-existent resources)
163 changes: 163 additions & 0 deletions apps/web/test/e2e/BUGS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# E2E Test Bugs

This file documents known bugs that block E2E tests.

---

## Namespace Bugs

### GET /api/v1/namespace/{namespaceId} - Cache Date Serialization Bug

**Status:** Failing
**Endpoint:** `GET /api/v1/namespace/{namespaceId}`
**Test:** `namespace.test.ts` → "should return namespace details"

#### Issue

The `unstable_cache` in `withNamespaceApiHandler` serializes `Date` objects to ISO strings. When `NamespaceSchema.parse()` runs, it expects a `Date` but receives a `string`.

#### Error Response

```json
{
"success": false,
"error": {
"code": "unprocessable_entity",
"message": "invalid_type: createdAt: Invalid input: expected date, received string"
}
}
```

#### Root Cause

**File:** [src/lib/api/handler/namespace.ts](../../src/lib/api/handler/namespace.ts)

The cache serializes Date objects to strings, but the schema validation expects Date objects.

#### Fix Options

1. Use `z.coerce.date()` in NamespaceSchema
2. Transform dates after cache retrieval
3. Add date normalization layer

---

## Hosting Bugs

### PATCH /api/v1/namespace/{namespaceId}/hosting - rerankConfig Corruption

**Status:** Failing
**Endpoint:** `PATCH /api/v1/namespace/{namespaceId}/hosting`
**Test:** `hosting.test.ts` → "should update hosting config"

#### Issue

When PATCH is called on hosting that doesn't have `rerankConfig` set (null), the update service creates an empty object `{}` which fails validation when the response is serialized.

#### Error Response

```json
{
"success": false,
"error": {
"code": "unprocessable_entity",
"message": "invalid_value: rerankConfig.model: Invalid option: expected one of \"cohere:rerank-v3.5\"..."
}
}
```

#### Root Cause

**File:** [src/services/hosting/update.ts](../../src/services/hosting/update.ts#L54-L55)

```typescript
const newRerankConfig = hosting.rerankConfig
? structuredClone(hosting.rerankConfig)
: ({} as PrismaJson.HostingRerankConfig);
```

When `hosting.rerankConfig` is null, it creates `{}` which doesn't have a valid `model` property.

Then in line 85:
```typescript
...(newRerankConfig && { rerankConfig: newRerankConfig }),
```

The truthy empty object `{}` is included in the update.

#### Fix Options

1. **Don't create empty object when rerankConfig is null:**
```typescript
const newRerankConfig = hosting.rerankConfig
? structuredClone(hosting.rerankConfig)
: null;
```

2. **Only include rerankConfig when it has valid data:**
```typescript
...(newRerankConfig?.model && { rerankConfig: newRerankConfig }),
```

---

### DELETE /api/v1/namespace/{namespaceId}/hosting - Response Serialization Error

**Status:** Failing (but operation succeeds)
**Endpoint:** `DELETE /api/v1/namespace/{namespaceId}/hosting`
**Test:** `hosting.test.ts` → "should delete hosting"

#### Issue

The DELETE endpoint successfully deletes the hosting record but returns a 500 error when trying to serialize the deleted hosting object in the response.

#### Error Response

```json
{
"success": false,
"error": {
"code": "internal_server_error",
"message": "An internal server error occurred..."
}
}
```

**Note:** The hosting IS successfully deleted despite the error response.

#### Root Cause

**File:** [src/app/api/(public-api)/v1/namespace/[namespaceId]/hosting/route.ts](../../src/app/api/(public-api)/v1/namespace/[namespaceId]/hosting/route.ts#L70-L85)

The DELETE handler:
1. Gets the hosting record
2. Deletes it
3. Tries to return the deleted hosting with `HostingSchema.parse()`

The issue is likely related to the same rerankConfig validation issue - if the hosting had corrupted data, the response parsing fails.

#### Fix Options

1. **Return a simpler response after delete:**
```typescript
return makeApiSuccessResponse({
data: { deleted: true },
headers,
status: 204,
});
```

2. **Don't return body for 204 responses:**
```typescript
return new Response(null, { status: 204, headers });
```

---

## Summary

| Bug | Endpoint | Impact | Workaround |
|-----|----------|--------|------------|
| Cache Date Serialization | GET namespace | Response validation fails | Test skipped |
| rerankConfig Corruption | PATCH hosting | Can't update hosting config | Don't use PATCH |
| DELETE Response Error | DELETE hosting | Returns 500 (but deletes) | Ignore response, check GET returns 404 |
Loading