Skip to content

test(integration-tests): add Emulate.dev-backed tests for the GitHub adapter#479

Merged
bensabic merged 7 commits into
mainfrom
tests/github-emulator-integration
May 12, 2026
Merged

test(integration-tests): add Emulate.dev-backed tests for the GitHub adapter#479
bensabic merged 7 commits into
mainfrom
tests/github-emulator-integration

Conversation

@bensabic

@bensabic bensabic commented May 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Add an Emulate.dev-backed integration-test suite for the GitHub adapter, mirroring the structure of the Slack work in #477. Tests drive the adapter against an in-process @emulators/github server and assert on its stateful store (comments, reviews) rather than mock.calls, catching wire-format and contract issues that pure Octokit mocks miss.

  • New private devDeps in packages/integration-tests: @emulators/github, @emulators/core, @hono/node-server, plus a workspace dep on @chat-adapter/github. (@emulators/core and @hono/node-server are also declared by test(integration-tests): add Emulate.dev-backed tests for the Slack adapter #477; this PR is independent of merge order.)
  • New harness packages/integration-tests/src/github-emulator-utils.ts boots the emulator on an ephemeral 127.0.0.1 port, seeds a deterministic user / repo / issue / PR / starter review comment, and exposes a near-passthrough HTTP forwarder. No re-signing needed here. @emulators/core's WebhookDispatcher already signs deliveries with X-Hub-Signature-256: sha256=<hex> exactly as the GitHub adapter expects. The harness also adds a small URL rewriter for Octokit's pulls.createReplyForReviewComment shortcut endpoint, translating it into the canonical review-comment POST that the emulator implements.
  • Four new test files (12 tests), wired to the adapter via its existing apiUrl + webhookSecret config zero source changes to packages/adapter-github:
    • emulator-github-auth.test.ts (2) GET /user populates botUserId during initialize().
    • emulator-github-comments.test.ts (4) thread.post / edit / delete on issue and PR-conversation threads.
    • emulator-github-reviews.test.ts (3) review-comment replies routed through pulls.createReplyForReviewComment with the right `in_reply_to_id`, plus edit / delete.
    • emulator-github-events.test.ts (3) full inbound issue_comment / pull_request_review_comment round-trip, including bot self-message filtering.
flowchart LR
  subgraph Test["Vitest test process"]
    SDK[GitHubAdapter + Chat]
    Forwarder["HTTP forwarder<br/>passthrough"]
    Emu["@emulators/github<br/>(in-process Hono)"]
  end

  SDK -->|"issues.createComment / pulls.* / GET /user<br/>(apiUrl override)"| Emu
  Emu -->|"X-Hub-Signature-256 + x-github-event"| Forwarder
  Forwarder -->|"chat.webhooks.github(request)"| SDK
Loading

Out of scope (deliberate)

  • Reactions @emulators/github does not implement the /reactions endpoints used by the adapter. Reaction logic is still covered by the existing mock-based tests in packages/adapter-github/src/index.test.ts.
  • GitHub App auth (JWT \u2192 installation token via POST /app/installations/:id/access_tokens) the adapter and emulator both support it, but PAT-mode was the agreed scope here.
  • Multi-tenant install flows via installation webhook events.
  • Branches/refs, releases, search, actions, checks not used by the adapter.

Test plan

  • pnpm --filter @chat-adapter/integration-tests test 407 tests pass across 34 files (including the 12 new emulator-github tests, ~480 ms total).
  • pnpm check and pnpm knip clean.
  • CI safety verified: ephemeral ports (port: 0), loopback-only binds (127.0.0.1), deterministic teardown via httpServer.close(), no env vars, no external network egress.

Checklist

  • All commits are signed and verified
  • `pnpm validate` passes
  • Changeset added (or N/A see CONTRIBUTING.md) N/A: `@chat-adapter/integration-tests` is `private: true` and the change is test-only.
  • Documentation updated (or N/A) `packages/integration-tests/README.md` describes the new emulator-github test category.

bensabic added 5 commits May 10, 2026 17:29
Add @emulators/github plus its supporting infrastructure (@emulators/core
and @hono/node-server) and a workspace dep on @chat-adapter/github to
the private integration-tests package. These power the upcoming
in-process GitHub emulator harness used to drive the GitHub adapter
against a stateful, GitHub-shaped HTTP server instead of mocks.

@emulators/core and @hono/node-server are also pulled in by the Slack
emulator work; declaring them explicitly here keeps this PR independent
of merge order.
Introduce github-emulator-utils.ts, a test-only helper that boots the
@emulators/github Hono app on an ephemeral 127.0.0.1 port via
@hono/node-server and pre-seeds a deterministic bot user / human user /
repo / issue / PR / starter review comment / OAuth app. The GitHub
adapter is wired to it via its existing apiUrl config; no source
changes required.

Unlike the Slack helper, no signing bridge is needed. The emulator's
core WebhookDispatcher already signs deliveries with
`X-Hub-Signature-256: sha256=<hex>` whenever a subscription has a
`secret`, which matches the GitHub adapter's verifier exactly. The
`startGitHubWebhookForwarder` is therefore a near-passthrough that just
copies the dispatcher's GitHub-style headers (`x-github-event`,
`x-github-delivery`, `x-hub-signature-256`) onto a Web `Request` and
hands it to a supplied `onWebhook` callback.

The harness also adds a small URL rewriter for Octokit's
`pulls.createReplyForReviewComment` shortcut endpoint (POST
`/comments/:id/replies`), translating it into the canonical review-
comment POST with `in_reply_to_id` that the emulator implements
natively.

The handle returns direct access to the emulator's Store and
WebhookDispatcher so tests can assert on persisted state instead of
mock call records.
Add two test files that drive the GitHubAdapter's outbound Octokit
calls through the in-process emulator and assert on its stateful store
rather than on mock call records:

- emulator-github-auth.test.ts (2 tests): GET /user populates botUserId
  during initialize() (proving the Octokit client correctly reaches the
  emulator); explicit botUserId is respected without calling /user.
- emulator-github-comments.test.ts (4 tests): thread.post on an
  issue-thread routes through `issues.createComment` and shows up as a
  comment with `comment_type: "issue"` and the right issue_number;
  the same flow on a PR-conversation thread works; editMessage routes
  through `issues.updateComment`; deleteMessage routes through
  `issues.deleteComment`.

These exercise the full HTTP path against a GitHub-shaped server,
catching wire-format and contract issues that pure Octokit mocks miss.
…hooks via emulator

Add two test files that drive end-to-end GitHub flows previously only
verifiable against real GitHub:

- emulator-github-reviews.test.ts (3 tests): posting on a review-
  comment thread routes through `pulls.createReplyForReviewComment`
  (with the harness translating Octokit's `/replies` shortcut into the
  emulator's canonical POST) and the resulting comment carries the
  right `in_reply_to_id` and `comment_type: "review"`. editMessage and
  deleteMessage round-trip via the review-comment endpoints.
- emulator-github-events.test.ts (3 tests): a human posts on a seeded
  issue, the emulator dispatches an `issue_comment` event with a real
  X-Hub-Signature-256, the forwarder hands the request straight to
  chat.webhooks.github(...), the SDK's onNewMessage runs with a live
  Thread, and the bot's reply lands back in the emulator. Variant for
  pull_request_review_comment that exercises the rc:<id> review-thread
  routing. Bot self-messages are correctly filtered.

This is the only integration test that covers the full inbound-then-
outbound GitHub round-trip without hand-crafted webhook payloads.
Add an "Emulator tests" entry to the package README so newcomers can
distinguish the new emulator-backed GitHub suite from the existing
unit and replay tests, and find the harness in
github-emulator-utils.ts.
@bensabic bensabic requested a review from a team as a code owner May 10, 2026 07:34
@vercel

vercel Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chat-sdk-nextjs-chat Ready Ready Preview, Comment May 12, 2026 10:08am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
chat Ignored Ignored May 12, 2026 10:08am

@socket-security

socket-security Bot commented May 10, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​emulators/​github@​0.5.07810010092100

View full report

@bensabic bensabic requested a review from HugoRCD May 10, 2026 07:36
…mulator/github/

Mirror the layout already used by the Slack emulator suite. Move the
flat `emulator-github-*.test.ts` files plus `github-emulator-utils.ts`
into a per-adapter directory:

  packages/integration-tests/src/emulator/github/
      utils.ts
      auth.test.ts
      comments.test.ts
      events.test.ts
      reviews.test.ts

Also hoist the duplicated `silentLogger` definition from each test file
into the shared `utils.ts`, removing four identical copies.

README updated to point at the new helper path. No behavior changes.
All 12 GitHub emulator tests still pass.
…-integration

# Conflicts:
#	packages/integration-tests/README.md
#	packages/integration-tests/package.json
#	pnpm-lock.yaml
@bensabic bensabic merged commit cd7b6af into main May 12, 2026
17 checks passed
@bensabic bensabic deleted the tests/github-emulator-integration branch May 12, 2026 21:12
patrick-chinchill added a commit to Chinchill-AI/chat-sdk-python that referenced this pull request Jun 20, 2026
…4662309 — TG4/4) (#166)

Rewrite the Telegram outbound stream/send/edit path around the native
rich-message Bot API with a rich -> MarkdownV2 -> plain fallback ladder,
mirroring upstream vercel/chat#479.

- Add resolve_rich_message, send_regular_message,
  can_fallback_from_rich_message, remember_rich_message_failure,
  with_telegram_rich_fallback, and the _rich_messages_available latch.
- stream(): drafts via sendRichMessageDraft + final sendRichMessage;
  drop the empty opening draft; move the final flush AFTER renderer
  finish() so a held-back trailing table block is flushed post-finish.
- post_message / edit_message: route {markdown}/{ast} through the rich
  endpoints and reuse the pre-rendered AST/text via TelegramParsedContent.
- resolve_rich_message gate is a disjunction including 'raw' key PRESENCE
  (not truthiness); can_fallback (transient-tolerant) and
  remember_failure (only latches off on missing/unsupported/404) are two
  distinct predicates — a transient can't-parse never disables rich.

Tests: rewrite the streaming suite for the rich ladder (non-streaming
rich send, rich draft streaming with the dropped-opening-draft call
count, flush-after-finish via a held-back table, rich markdown preserved,
404/ResourceNotFound permanent flag flip, transient can't-parse per-
message fallback) plus direct unit tests for the two predicates and the
resolve gate. Fold in the TG3 inbound entities nullish-ladder test
(empty entities: [] does not fall through to caption_entities).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants