@rivetkit/core
Version:
248 lines (207 loc) • 8.49 kB
text/typescript
import { describe, expect, test } from "vitest";
import type { DriverTestConfig } from "../mod";
import { setupDriverTest } from "../utils";
export function runRequestAccessTests(driverTestConfig: DriverTestConfig) {
describe("Request Access in Lifecycle Hooks", () => {
test("should have access to request object in onBeforeConnect and createConnState", async (c) => {
const { client } = await setupDriverTest(c, driverTestConfig);
// Create actor with request tracking enabled
const handle = client.requestAccessActor.getOrCreate(["test-request"], {
params: { trackRequest: true },
});
const connection = await handle.connect();
// Get request info that was captured in onBeforeConnect
const requestInfo = await connection.getRequestInfo();
// Verify request was accessible in HTTP mode, but not in inline mode
if (driverTestConfig.clientType === "http") {
// Check onBeforeConnect
expect(requestInfo.onBeforeConnect.hasRequest).toBe(true);
expect(requestInfo.onBeforeConnect.requestUrl).toBeDefined();
expect(requestInfo.onBeforeConnect.requestMethod).toBeDefined();
expect(requestInfo.onBeforeConnect.requestHeaders).toBeDefined();
// Check createConnState
expect(requestInfo.createConnState.hasRequest).toBe(true);
expect(requestInfo.createConnState.requestUrl).toBeDefined();
expect(requestInfo.createConnState.requestMethod).toBeDefined();
expect(requestInfo.createConnState.requestHeaders).toBeDefined();
} else {
// Inline client doesn't have request object
expect(requestInfo.onBeforeConnect.hasRequest).toBe(false);
expect(requestInfo.onBeforeConnect.requestUrl).toBeNull();
expect(requestInfo.onBeforeConnect.requestMethod).toBeNull();
expect(requestInfo.createConnState.hasRequest).toBe(false);
expect(requestInfo.createConnState.requestUrl).toBeNull();
expect(requestInfo.createConnState.requestMethod).toBeNull();
}
// Clean up
await connection.dispose();
});
test("should not have request when trackRequest is false", async (c) => {
const { client } = await setupDriverTest(c, driverTestConfig);
// Create actor without request tracking
const handle = client.requestAccessActor.getOrCreate(
["test-no-request"],
{
params: { trackRequest: false },
},
);
const connection = await handle.connect();
// Get request info
const requestInfo = await connection.getRequestInfo();
// Verify request was not tracked
expect(requestInfo.onBeforeConnect.hasRequest).toBe(false);
expect(requestInfo.onBeforeConnect.requestUrl).toBeNull();
expect(requestInfo.onBeforeConnect.requestMethod).toBeNull();
expect(
Object.keys(requestInfo.onBeforeConnect.requestHeaders),
).toHaveLength(0);
expect(requestInfo.createConnState.hasRequest).toBe(false);
expect(requestInfo.createConnState.requestUrl).toBeNull();
expect(requestInfo.createConnState.requestMethod).toBeNull();
expect(
Object.keys(requestInfo.createConnState.requestHeaders),
).toHaveLength(0);
// Clean up
await connection.dispose();
});
test("should capture request headers and method", async (c) => {
const { client } = await setupDriverTest(c, driverTestConfig);
// Create actor and connect with request tracking
const handle = client.requestAccessActor.getOrCreate(["test-headers"], {
params: { trackRequest: true },
});
const connection = await handle.connect();
// Get request info
const requestInfo = await connection.getRequestInfo();
if (driverTestConfig.clientType === "http") {
// Verify request details were captured in both hooks
expect(requestInfo.onBeforeConnect.hasRequest).toBe(true);
expect(requestInfo.onBeforeConnect.requestMethod).toBeTruthy();
expect(requestInfo.onBeforeConnect.requestUrl).toBeTruthy();
expect(requestInfo.onBeforeConnect.requestHeaders).toBeTruthy();
expect(typeof requestInfo.onBeforeConnect.requestHeaders).toBe(
"object",
);
expect(requestInfo.createConnState.hasRequest).toBe(true);
expect(requestInfo.createConnState.requestMethod).toBeTruthy();
expect(requestInfo.createConnState.requestUrl).toBeTruthy();
expect(requestInfo.createConnState.requestHeaders).toBeTruthy();
expect(typeof requestInfo.createConnState.requestHeaders).toBe(
"object",
);
} else {
// Inline client doesn't have request object
expect(requestInfo.onBeforeConnect.hasRequest).toBe(false);
expect(requestInfo.createConnState.hasRequest).toBe(false);
}
// Clean up
await connection.dispose();
});
test("should have access to request object in onAuth", async (c) => {
const { client, endpoint } = await setupDriverTest(c, driverTestConfig);
// Only test in HTTP mode as onAuth only runs for public endpoints
if (driverTestConfig.clientType === "http") {
// For now, skip this test as onAuth might not be properly invoked in test environment
// The onAuth hook is designed for public endpoints and might require special setup
console.log("Skipping onAuth test - requires public endpoint setup");
// TODO: Implement proper public endpoint test for onAuth
// This would require setting up the actor with public access and making
// requests from outside the internal client
}
});
test("should have access to request object in onFetch", async (c) => {
const { client, endpoint } = await setupDriverTest(c, driverTestConfig);
// Create actor
const handle = client.requestAccessActor.getOrCreate(["test-fetch"]);
// Make a raw HTTP request to the actor
await handle.resolve(); // Ensure actor is created
const actorQuery = {
getOrCreateForKey: {
name: "requestAccessActor",
key: ["test-fetch"],
},
};
const url = `${endpoint}/registry/actors/raw/http/test-path`;
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Test-Header": "test-value",
"X-RivetKit-Query": JSON.stringify(actorQuery),
},
body: JSON.stringify({ test: "data" }),
});
if (!response.ok) {
const errorText = await response.text();
console.error(
`HTTP request failed: ${response.status} ${response.statusText}`,
errorText,
);
}
expect(response.ok).toBe(true);
const data = await response.json();
// Verify request info from onFetch
expect((data as any).hasRequest).toBe(true);
expect((data as any).requestUrl).toContain("/test-path");
expect((data as any).requestMethod).toBe("POST");
expect((data as any).requestHeaders).toBeDefined();
expect((data as any).requestHeaders["content-type"]).toBe(
"application/json",
);
expect((data as any).requestHeaders["x-test-header"]).toBe("test-value");
});
test("should have access to request object in onWebSocket", async (c) => {
const { client, endpoint } = await setupDriverTest(c, driverTestConfig);
// Only test in environments that support WebSocket
if (typeof WebSocket !== "undefined") {
// Create actor
const handle = client.requestAccessActor.getOrCreate([
"test-websocket",
]);
await handle.resolve(); // Ensure actor is created
const actorQuery = {
getOrCreateForKey: {
name: "requestAccessActor",
key: ["test-websocket"],
},
};
// Encode query as WebSocket subprotocol
const queryProtocol = `query.${encodeURIComponent(JSON.stringify(actorQuery))}`;
// Create raw WebSocket connection
const wsUrl = endpoint
.replace("http://", "ws://")
.replace("https://", "wss://");
const ws = new WebSocket(
`${wsUrl}/registry/actors/raw/websocket/test-path`,
[
queryProtocol,
"rivetkit", // Required protocol
],
);
// Wait for connection and first message
await new Promise<void>((resolve, reject) => {
ws.onopen = () => {
// Connection established
};
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
// Verify request info from onWebSocket
expect(data.hasRequest).toBe(true);
expect(data.requestUrl).toContain("/test-path");
expect(data.requestMethod).toBe("GET");
expect(data.requestHeaders).toBeDefined();
ws.close();
resolve();
} catch (error) {
reject(error);
}
};
ws.onerror = (error) => {
reject(error);
};
});
}
});
});
}