mirror of
http://100.103.83.12:3003/fegger/time_to_leave.git
synced 2026-09-17 09:42:44 +00:00
Add mobile services, web proxy, and Gemma4 agent loop
- Mobile: add push notification and calendar sync services with full test suite (calendar, eventStore, notifications, screens) - Mobile: add EAS build config and Jest setup - Web: add API proxy, update useDestinationStation/useJourneys hooks, add middleware tests - Web: update next.config and rebuild - Agent: add Gemma4-based agent loop (agent_base, ttl_agent, ts_agent) - Docs: add privacy policy, post-MVP plan, and aider rules
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { NextRequest } from 'next/server';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import proxy from '../proxy';
|
||||
|
||||
// Mock NextResponse to avoid internal routing context issues
|
||||
vi.mock('next/server', async (importOriginal) => {
|
||||
const actual = await importOriginal()
|
||||
|
||||
// Create a mock constructor class with static methods
|
||||
class MockNextResponse {
|
||||
public headers: Headers;
|
||||
public status: number;
|
||||
public statusText: string;
|
||||
public body: BodyInit | null;
|
||||
|
||||
static next: () => MockNextResponse;
|
||||
static json: () => void;
|
||||
static redirect: () => void;
|
||||
|
||||
constructor(_init?: ResponseInit) {
|
||||
this.headers = new Headers();
|
||||
this.status = _init?.status ?? 200;
|
||||
this.statusText = 'OK';
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
clone() { return new MockNextResponse(); }
|
||||
arrayBuffer() { return new ArrayBuffer(0); }
|
||||
blob() { return new Blob(); }
|
||||
formData() { return new FormData(); }
|
||||
json() { return {}; }
|
||||
text() { return ''; }
|
||||
}
|
||||
|
||||
// Static methods
|
||||
MockNextResponse.next = vi.fn(() => new MockNextResponse());
|
||||
MockNextResponse.json = vi.fn();
|
||||
MockNextResponse.redirect = vi.fn();
|
||||
|
||||
return {
|
||||
...actual as Record<string, unknown>,
|
||||
NextResponse: MockNextResponse,
|
||||
}
|
||||
});
|
||||
|
||||
describe('middleware', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should bypass non-API requests', () => {
|
||||
const request = new NextRequest('http://localhost:3000/test', {
|
||||
headers: { origin: 'http://localhost:3000' },
|
||||
});
|
||||
|
||||
const response = proxy(request);
|
||||
expect(response).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle preflight requests for API routes', () => {
|
||||
const request = new NextRequest('http://localhost:3000/api/test', {
|
||||
method: 'OPTIONS',
|
||||
headers: { origin: 'http://localhost:3000' },
|
||||
});
|
||||
|
||||
const response = proxy(request);
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
|
||||
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('GET, POST, PUT, DELETE, OPTIONS');
|
||||
expect(response.headers.get('Access-Control-Allow-Headers')).toBe('Content-Type, Authorization');
|
||||
expect(response.headers.get('Access-Control-Max-Age')).toBe('86400');
|
||||
expect(response.headers.get('Vary')).toBe('Origin');
|
||||
});
|
||||
|
||||
it('should handle regular API requests with cross-origin', () => {
|
||||
const request = new NextRequest('http://localhost:3000/api/test', {
|
||||
headers: { origin: 'http://different-origin.com' },
|
||||
});
|
||||
|
||||
const response = proxy(request);
|
||||
expect(response).toBeDefined();
|
||||
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
|
||||
expect(response.headers.get('Vary')).toBe('Origin');
|
||||
});
|
||||
|
||||
it('should handle API requests without Origin header', () => {
|
||||
const request = new NextRequest('http://localhost:3000/api/test', {
|
||||
headers: {},
|
||||
});
|
||||
|
||||
const response = proxy(request);
|
||||
expect(response).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user