mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Double default timeouts and extend the explicit waitForFeedItems calls across the e2e test suite to accommodate slower CI runners. This allows the docs-code-investigator scheduler run to pass successfully without being artificially blocked by environmental flakiness. Co-authored-by: PR0M3TH3AN <[email protected]>
264 lines
7.7 KiB
TypeScript
264 lines
7.7 KiB
TypeScript
/**
|
|
* Relay connection failure, fallback, and health monitoring tests.
|
|
*
|
|
* Scenarios covered:
|
|
* - SCN-relay-health: Relay health endpoint reports connection state
|
|
* - SCN-relay-override: setTestRelays properly overrides relay config
|
|
* - SCN-relay-multiple: Multiple relay URLs can be configured
|
|
* - SCN-relay-health-monitoring: getRelayHealth returns actionable data
|
|
* - SCN-relay-event-seeding: Events seeded to relay are retrievable
|
|
* - SCN-relay-clear-recovery: App survives relay clear mid-session
|
|
* - SCN-relay-http-api: Full HTTP API lifecycle (seed, list, clear, health)
|
|
*/
|
|
|
|
import { test, expect } from "./helpers/bitvidTestFixture";
|
|
|
|
test.describe("Relay resilience and management", () => {
|
|
test.describe("Relay HTTP API lifecycle", () => {
|
|
test("full relay API lifecycle: seed, list, health, clear", async ({
|
|
relay,
|
|
seedEvent,
|
|
clearRelay,
|
|
}) => {
|
|
const httpUrl = (relay as any).httpUrl;
|
|
|
|
// Step 1: Health check on empty relay
|
|
let healthResp = await fetch(`${httpUrl}/health`);
|
|
let health = await healthResp.json();
|
|
expect(health.ok).toBe(true);
|
|
expect(health.eventCount).toBe(0);
|
|
|
|
// Step 2: Seed events
|
|
await seedEvent({
|
|
title: "Relay Test A",
|
|
url: "https://example.com/a.mp4",
|
|
dTag: "relay-a",
|
|
});
|
|
await seedEvent({
|
|
title: "Relay Test B",
|
|
url: "https://example.com/b.mp4",
|
|
dTag: "relay-b",
|
|
});
|
|
|
|
// Step 3: Verify events are listed
|
|
let eventsResp = await fetch(`${httpUrl}/events`);
|
|
let events = await eventsResp.json();
|
|
expect(events.length).toBe(2);
|
|
|
|
// Step 4: Health reflects event count
|
|
healthResp = await fetch(`${httpUrl}/health`);
|
|
health = await healthResp.json();
|
|
expect(health.eventCount).toBe(2);
|
|
|
|
// Step 5: Clear events
|
|
await clearRelay();
|
|
|
|
// Step 6: Verify clear worked
|
|
eventsResp = await fetch(`${httpUrl}/events`);
|
|
events = await eventsResp.json();
|
|
expect(events.length).toBe(0);
|
|
|
|
healthResp = await fetch(`${httpUrl}/health`);
|
|
health = await healthResp.json();
|
|
expect(health.eventCount).toBe(0);
|
|
});
|
|
|
|
test("seeding multiple events preserves all data", async ({
|
|
relay,
|
|
seedEvent,
|
|
}) => {
|
|
const httpUrl = (relay as any).httpUrl;
|
|
|
|
// Seed 5 events with distinct d-tags
|
|
for (let i = 0; i < 5; i++) {
|
|
await seedEvent({
|
|
title: `Batch Video ${i}`,
|
|
url: `https://example.com/batch-${i}.mp4`,
|
|
dTag: `batch-${i}`,
|
|
});
|
|
}
|
|
|
|
// All 5 should be retrievable
|
|
const resp = await fetch(`${httpUrl}/events`);
|
|
const events = await resp.json();
|
|
expect(events.length).toBe(5);
|
|
|
|
// Verify each event has unique content
|
|
const titles = events.map((e: any) => JSON.parse(e.content).title);
|
|
for (let i = 0; i < 5; i++) {
|
|
expect(titles).toContain(`Batch Video ${i}`);
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe("Relay configuration via test harness", () => {
|
|
test("setTestRelays overrides both relayManager and nostrClient", async ({
|
|
page,
|
|
gotoApp,
|
|
relayUrl,
|
|
setTestRelays,
|
|
}) => {
|
|
// Given: the app is loaded
|
|
await gotoApp();
|
|
|
|
// When: we set relay URLs via the harness
|
|
const result = await setTestRelays(page, [relayUrl]);
|
|
|
|
// Then: both relay systems are aligned
|
|
expect(result.ok).toBe(true);
|
|
|
|
const state = await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.getAppState();
|
|
});
|
|
expect(state.relays.read).toEqual([relayUrl]);
|
|
expect(state.relayManager.read).toEqual([relayUrl]);
|
|
});
|
|
|
|
test("setTestRelays accepts multiple relay URLs", async ({
|
|
page,
|
|
gotoApp,
|
|
relayUrl,
|
|
setTestRelays,
|
|
}) => {
|
|
// Given: the app is loaded
|
|
await gotoApp();
|
|
|
|
// When: we configure multiple relays (one real, one fake)
|
|
const fakeRelay = "ws://127.0.0.1:9999";
|
|
const result = await setTestRelays(page, [relayUrl, fakeRelay]);
|
|
|
|
// Then: both are registered
|
|
expect(result.ok).toBe(true);
|
|
|
|
const state = await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.getAppState();
|
|
});
|
|
expect(state.relays.read).toContain(relayUrl);
|
|
expect(state.relays.read).toContain(fakeRelay);
|
|
});
|
|
|
|
test("relay overrides are applied via query params on load", async ({
|
|
page,
|
|
gotoApp,
|
|
relayUrl,
|
|
}) => {
|
|
// Given/When: the app is loaded with relay overrides in URL
|
|
await gotoApp();
|
|
|
|
// Then: app state reflects the override
|
|
const state = await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.getAppState();
|
|
});
|
|
expect(state.relays).toBeTruthy();
|
|
const allRelays = state.relays.all || [];
|
|
expect(allRelays).toContain(relayUrl);
|
|
});
|
|
});
|
|
|
|
test.describe("Relay health monitoring", () => {
|
|
test("getRelayHealth returns structured data", async ({
|
|
page,
|
|
gotoApp,
|
|
}) => {
|
|
// Given: the app is loaded with relay connections
|
|
await gotoApp();
|
|
|
|
// When: we query relay health
|
|
const health = await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.getRelayHealth();
|
|
});
|
|
|
|
// Then: health info contains expected fields
|
|
expect(health).toBeTruthy();
|
|
expect(health.relays).toBeDefined();
|
|
expect(Array.isArray(health.unreachable) || health.unreachable === undefined).toBe(true);
|
|
});
|
|
|
|
test("relay health reports after login", async ({
|
|
page,
|
|
gotoApp,
|
|
loginAs,
|
|
}) => {
|
|
// Given: a logged-in user
|
|
await gotoApp();
|
|
await loginAs(page);
|
|
|
|
// When: we check relay health
|
|
const health = await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.getRelayHealth();
|
|
});
|
|
|
|
// Then: health data is available
|
|
expect(health).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
test.describe("Recovery after relay operations", () => {
|
|
test("app remains functional after clearing relay events", async ({
|
|
page,
|
|
gotoApp,
|
|
loginAs,
|
|
seedEvent,
|
|
clearRelay,
|
|
}) => {
|
|
// Given: videos in the relay and a logged-in user
|
|
await seedEvent({
|
|
title: "Before Clear Video",
|
|
url: "https://example.com/before.mp4",
|
|
dTag: "before-clear-001",
|
|
});
|
|
|
|
await gotoApp();
|
|
await loginAs(page);
|
|
|
|
// When: relay events are cleared
|
|
await clearRelay();
|
|
|
|
// Then: app state remains valid (no crash)
|
|
const state = await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.getAppState();
|
|
});
|
|
expect(state.isLoggedIn).toBe(true);
|
|
expect(state).toBeTruthy();
|
|
});
|
|
|
|
test("new events are discoverable after relay clear and re-seed", async ({
|
|
page,
|
|
gotoApp,
|
|
loginAs,
|
|
seedEvent,
|
|
clearRelay,
|
|
}) => {
|
|
// Given: initial events
|
|
await seedEvent({
|
|
title: "Old Video",
|
|
url: "https://example.com/old.mp4",
|
|
dTag: "reseed-old-001",
|
|
});
|
|
|
|
await gotoApp();
|
|
await loginAs(page);
|
|
|
|
// Wait for initial feed
|
|
await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.waitForFeedItems(1, 60000);
|
|
});
|
|
|
|
// When: clear and re-seed with different content
|
|
await clearRelay();
|
|
await seedEvent({
|
|
title: "Fresh Video After Clear",
|
|
url: "https://example.com/fresh.mp4",
|
|
dTag: "reseed-fresh-001",
|
|
});
|
|
|
|
// Then: app remains functional (state is valid)
|
|
const state = await page.evaluate(() => {
|
|
return (window as any).__bitvidTest__.getAppState();
|
|
});
|
|
expect(state).toBeTruthy();
|
|
expect(state.isLoggedIn).toBe(true);
|
|
});
|
|
});
|
|
});
|