Skip to content
Back to skills

Hamster E2e Realtime

ASecurity

Deterministic realtime E2E testing patterns for Supabase postgres_changes. Use when writing E2E tests that seed data via DB and expect it to appear in the browser via Supabase Realtime.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
testingtypescripttesting

Works with

  • cli

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 27, 2026

npx -y skills add gethamster/skills --skill hamster-e2e-realtime --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hamster E2e Realtime?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hamster E2e Realtime
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gethamster-hamster-e2e-realtime/badge)](https://www.skillsdirectory.com/skills/gethamster-hamster-e2e-realtime)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hamster-e2e-realtime
description: "Deterministic realtime E2E testing patterns for Supabase postgres_changes. Use when writing E2E tests that seed data via DB and expect it to appear in the browser via Supabase Realtime."
version: "1.0.0"
---

# Hamster E2E Realtime Testing Patterns

## Overview

Deterministic patterns for E2E tests that seed data via Supabase admin client and expect it to appear in the browser via `postgres_changes`. Eliminates flaky timeouts by guaranteeing subscription readiness before writing.

## When to Apply

- Writing E2E tests that insert/update data via admin client and expect realtime propagation
- Testing features that use `postgres_changes` (chat threads, Y.js document sync, live updates)
- Any test where the browser receives data via Supabase Realtime WebSocket

## Quick Reference

| Task | Pattern | Reference |
| --- | --- | --- |
| Seed data via DB with realtime delivery | Pre-subscribe → write → wait | [realtime-seeding.md](references/realtime-seeding.md) |
| Wait for browser channel subscription | WebSocket interception | [browser-interception.md](references/browser-interception.md) |
| Wait for server-side event delivery | `waitForRealtimeEvent` | [server-listener.md](references/server-listener.md) |

## Core Pattern

```typescript
// 1. Wait for browser's realtime channel to be subscribed
await pageObject.waitForDocumentChannelSubscribed(documentId);

// 2. Set up server-side listener
const rt = waitForRealtimeEvent({
  table: 'document',
  filter: `id=eq.${documentId}`,
  event: 'UPDATE',
});
await rt.subscribed;

// 3. Write to DB — both browser and test harness are listening
await adminClient.from('document').update({ ... }).eq('id', documentId);

// 4. Wait for event delivery confirmation
await rt.event;

// 5. Assert UI updated
await expect(page.locator('[data-test="tiptap-editor"] img')).toHaveCount(1);
```

## Anti-Patterns (MUST NOT)

```typescript
// WRONG — arbitrary timeout, no subscription guarantee
await page.waitForTimeout(3000);
await adminClient.from('documents').update({ ... });

// WRONG — polling without subscription guarantee
await expect(async () => {
  const count = await page.locator('img').count();
  expect(count).toBeGreaterThanOrEqual(1);
}).toPass({ timeout: 30000 });
```

## Known Channel Names

| Feature | Channel Topic | Table | Event |
| --- | --- | --- | --- |
| Chat thread items | `realtime:thread:${threadId}:items` | `thread_items` | `INSERT` |
| Thread summary/metadata | `realtime:thread-summary:${threadId}` | `threads` | `UPDATE` |
| Y.js document sync | `realtime:yjs:doc:${documentId}` | `document` | `UPDATE` |

## Page Object Integration

POs that extend `ChatPageObject` have access to `this.realtimeInterceptor` (`protected`):

```typescript
export class MyFeaturePageObject extends BriefsPageObject {
  async waitForDocumentChannelSubscribed(documentId: string, timeoutMs = 15_000) {
    await this.realtimeInterceptor.waitForChannel(
      `realtime:yjs:doc:${documentId}`,
      timeoutMs,
    );
  }
}
```

## References

- [realtime-seeding.md](references/realtime-seeding.md) - Full deterministic seeding pattern with sequence diagram
- [browser-interception.md](references/browser-interception.md) - Browser-side WebSocket interception
- [server-listener.md](references/server-listener.md) - Server-side `waitForRealtimeEvent` utility

## Key Files

| File | Purpose |
| --- | --- |
| `apps/e2e/tests/utils/realtime.ts` | `waitForRealtimeEvent` — server-side listener |
| `apps/e2e/tests/utils/realtime-interception.ts` | `createRealtimeInterceptor` — browser WebSocket tracking |
| `apps/e2e/tests/chat/chat.po.ts` | `ChatPageObject` — base PO with realtime interceptor |
| `apps/e2e/tests/chat/utils/thread-seed-utils.ts` | Reference implementation (threads) |
| `packages/y-supabase/src/provider.ts` | `SupabaseCollabProvider` — channel naming, self-save filter |

Files in this skill

  • SKILL.md3.8 KB
  • references/browser-interception.md2.4 KB
  • references/realtime-seeding.md5.3 KB
  • references/server-listener.md2.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…