Skip to content

Commit c94a621

Browse files
Add shared fixtures module with JSON metadata
- Create shared/fixtures.ts with absolute path utilities - Read verification codes from JSON metadata (not hard-coded) - Add all PDF JSON metadata files from generate-pdfs.sh - Update fetch examples to use shared fixtures module - Add @ts-expect-error for missing 'provider' field in types - All examples now work from any directory using absolute paths - Tests: 4/4 passing for all-sizes example
1 parent 50fb8ed commit c94a621

File tree

8 files changed

+151
-47
lines changed

8 files changed

+151
-47
lines changed

fixtures/pdfs/large.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"size": "large",
3+
"description": "Large PDF test fixture (3.4 MB) for FileParserPlugin regression testing",
4+
"verificationCode": "LARGE-M9N3T",
5+
"fileSizeBytes": 3567616,
6+
"generatedDate": "2025-11-06"
7+
}

fixtures/pdfs/medium.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"verificationCode": "MEDIUM-K4P8R",
3+
"description": "Medium test PDF (813KB) with text and image padding",
4+
"size": "medium",
5+
"type": "test_fixture",
6+
"purpose": "Test PDF processing with moderate file size"
7+
}

fixtures/pdfs/small.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"verificationCode": "SMALL-7X9Q2",
3+
"description": "Small test PDF (33KB) with minimal content",
4+
"size": "small",
5+
"type": "test_fixture",
6+
"purpose": "Test basic PDF processing with FileParserPlugin"
7+
}

fixtures/pdfs/xlarge.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"verificationCode": "XLARGE-W6H5V",
3+
"description": "Extra-large test PDF (11MB) with extensive content",
4+
"size": "xlarge",
5+
"type": "test_fixture",
6+
"purpose": "Test maximum file size handling with FileParserPlugin"
7+
}

typescript/fetch/src/plugin-file-parser/file-parser-all-sizes.ts

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,64 +11,36 @@
1111
* - PDFs are sent via base64-encoded data URLs
1212
* - Plugin must be explicitly configured in the request body
1313
* - Tests multiple PDF sizes: small (33KB), medium (813KB), large (3.4MB), xlarge (10.8MB)
14+
* - Uses shared fixtures module with absolute paths
1415
*
1516
* To run: bun run typescript/fetch/src/plugin-file-parser/file-parser-all-sizes.ts
1617
*/
1718

19+
import {
20+
PDF_SIZES,
21+
type PdfSize,
22+
extractCode,
23+
formatSize,
24+
getPdfSize,
25+
readExpectedCode,
26+
readPdfAsDataUrl,
27+
} from '@openrouter-examples/shared/fixtures';
1828
import type { ChatCompletionResponse } from '@openrouter-examples/shared/types';
1929

20-
// OpenRouter API endpoint
2130
const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';
2231

23-
// Expected verification codes from PDFs
24-
const EXPECTED_CODES: Record<string, string> = {
25-
small: 'SMALL-7X9Q2',
26-
medium: 'MEDIUM-K4P8R',
27-
large: 'LARGE-M9N3T',
28-
xlarge: 'XLARGE-W6H5V',
29-
};
30-
31-
/**
32-
* Convert PDF file to base64 data URL
33-
*/
34-
async function readPdfAsDataUrl(filePath: string): Promise<string> {
35-
const pdfFile = Bun.file(filePath);
36-
const pdfBuffer = await pdfFile.arrayBuffer();
37-
const base64PDF = Buffer.from(pdfBuffer).toString('base64');
38-
return `data:application/pdf;base64,${base64PDF}`;
39-
}
40-
41-
/**
42-
* Extract verification code from response text
43-
*/
44-
function extractCode(text: string): string | null {
45-
const match = text.match(/[A-Z]+-[A-Z0-9]{5}/);
46-
return match ? match[0] : null;
47-
}
48-
49-
/**
50-
* Format file size for display
51-
*/
52-
function formatSize(bytes: number): string {
53-
if (bytes < 1024 * 1024) {
54-
return `${(bytes / 1024).toFixed(0)} KB`;
55-
}
56-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
57-
}
58-
5932
/**
6033
* Make a request to process a PDF with FileParserPlugin
6134
*/
6235
async function processPdf(
63-
size: string,
36+
size: PdfSize,
6437
expectedCode: string,
6538
): Promise<{ success: boolean; extracted: string | null; usage?: unknown }> {
66-
const filePath = `./fixtures/pdfs/${size}.pdf`;
67-
const file = Bun.file(filePath);
68-
const dataUrl = await readPdfAsDataUrl(filePath);
39+
const dataUrl = await readPdfAsDataUrl(size);
40+
const fileSize = getPdfSize(size);
6941

7042
console.log(`\n=== ${size.toUpperCase()} PDF ===`);
71-
console.log(`Size: ${formatSize(file.size)}`);
43+
console.log(`Size: ${formatSize(fileSize)}`);
7244
console.log(`Expected: ${expectedCode}`);
7345

7446
if (!process.env.OPENROUTER_API_KEY) {
@@ -146,8 +118,9 @@ async function main() {
146118
const results: boolean[] = [];
147119

148120
try {
149-
for (const [size, expectedCode] of Object.entries(EXPECTED_CODES)) {
121+
for (const size of PDF_SIZES) {
150122
try {
123+
const expectedCode = await readExpectedCode(size);
151124
const result = await processPdf(size, expectedCode);
152125
results.push(result.success);
153126
} catch (error) {
@@ -167,10 +140,9 @@ async function main() {
167140
if (passed === total) {
168141
console.log('\n✅ All PDF sizes processed successfully!');
169142
process.exit(0);
170-
} else {
171-
console.log('\n❌ Some PDF tests failed');
172-
process.exit(1);
173143
}
144+
console.log('\n❌ Some PDF tests failed');
145+
process.exit(1);
174146
} catch (error) {
175147
console.error('\n❌ ERROR during testing:');
176148

typescript/fetch/src/plugin-file-parser/file-parser-pdf-url.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ async function examplePDFFromURL() {
8585

8686
console.log('✅ Request successful!');
8787
console.log('\nModel:', data.model);
88+
// FIXME: ChatCompletionResponse type is missing 'provider' field which exists in actual response
89+
// @ts-expect-error - provider field exists in response but not in type definition
8890
console.log('Provider:', data.provider);
8991
console.log('\nSummary:');
9092
console.log(data.choices[0].message.content);

typescript/shared/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
},
99
"exports": {
1010
"./constants": "./src/constants.ts",
11-
"./types": "./src/types.ts"
11+
"./types": "./src/types.ts",
12+
"./fixtures": "./src/fixtures.ts"
1213
},
1314
"devDependencies": {
1415
"@types/bun": "latest",

typescript/shared/src/fixtures.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* Shared utilities for working with PDF fixtures
3+
*
4+
* This module provides helpers to read PDF fixtures and their metadata
5+
* using absolute paths so examples work regardless of where they're run from.
6+
*/
7+
8+
import { dirname, join } from 'node:path';
9+
import { fileURLToPath } from 'node:url';
10+
11+
// Calculate absolute path to fixtures directory
12+
// This works from any location by resolving relative to this file
13+
const __filename = fileURLToPath(import.meta.url);
14+
const __dirname = dirname(__filename);
15+
const FIXTURES_DIR = join(__dirname, '../../../fixtures/pdfs');
16+
17+
export const PDF_SIZES = ['small', 'medium', 'large', 'xlarge'] as const;
18+
export type PdfSize = (typeof PDF_SIZES)[number];
19+
20+
export interface PdfMetadata {
21+
verificationCode: string;
22+
description: string;
23+
size: string;
24+
type: string;
25+
purpose: string;
26+
regression?: string;
27+
}
28+
29+
/**
30+
* Get absolute path to a PDF fixture file
31+
*/
32+
export function getPdfPath(size: PdfSize): string {
33+
return join(FIXTURES_DIR, `${size}.pdf`);
34+
}
35+
36+
/**
37+
* Get absolute path to a PDF metadata JSON file
38+
*/
39+
export function getMetadataPath(size: PdfSize): string {
40+
return join(FIXTURES_DIR, `${size}.json`);
41+
}
42+
43+
/**
44+
* Read verification code from JSON metadata
45+
*/
46+
export async function readExpectedCode(size: PdfSize): Promise<string> {
47+
const metadataPath = getMetadataPath(size);
48+
const file = Bun.file(metadataPath);
49+
const metadata = (await file.json()) as PdfMetadata;
50+
return metadata.verificationCode;
51+
}
52+
53+
/**
54+
* Read all expected codes for all PDF sizes
55+
*/
56+
export async function readAllExpectedCodes(): Promise<Record<PdfSize, string>> {
57+
const codes = await Promise.all(
58+
PDF_SIZES.map(async (size) => {
59+
const code = await readExpectedCode(size);
60+
return [size, code] as const;
61+
}),
62+
);
63+
return Object.fromEntries(codes) as Record<PdfSize, string>;
64+
}
65+
66+
/**
67+
* Convert PDF file to base64 data URL
68+
*/
69+
export async function readPdfAsDataUrl(size: PdfSize): Promise<string> {
70+
const pdfPath = getPdfPath(size);
71+
const pdfFile = Bun.file(pdfPath);
72+
const pdfBuffer = await pdfFile.arrayBuffer();
73+
const base64PDF = Buffer.from(pdfBuffer).toString('base64');
74+
return `data:application/pdf;base64,${base64PDF}`;
75+
}
76+
77+
/**
78+
* Get file size in bytes
79+
*/
80+
export function getPdfSize(size: PdfSize): number {
81+
const pdfPath = getPdfPath(size);
82+
return Bun.file(pdfPath).size;
83+
}
84+
85+
/**
86+
* Format file size for display
87+
*/
88+
export function formatSize(bytes: number): string {
89+
if (bytes < 1024 * 1024) {
90+
return `${(bytes / 1024).toFixed(0)} KB`;
91+
}
92+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
93+
}
94+
95+
/**
96+
* Extract verification code from response text using regex
97+
*/
98+
export function extractCode(text: string): string | null {
99+
const match = text.match(/[A-Z]+-[A-Z0-9]{5}/);
100+
return match ? match[0] : null;
101+
}

0 commit comments

Comments
 (0)