test(integration-tests): add Emulate.dev-backed tests for the GitHub adapter#479
Merged
Conversation
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.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
…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
visyat
approved these changes
May 12, 2026
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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/githubserver and assert on its stateful store (comments, reviews) rather thanmock.calls, catching wire-format and contract issues that pure Octokit mocks miss.packages/integration-tests:@emulators/github,@emulators/core,@hono/node-server, plus a workspace dep on@chat-adapter/github. (@emulators/coreand@hono/node-serverare also declared by test(integration-tests): add Emulate.dev-backed tests for the Slack adapter #477; this PR is independent of merge order.)packages/integration-tests/src/github-emulator-utils.tsboots the emulator on an ephemeral127.0.0.1port, seeds a deterministic user / repo / issue / PR / starter review comment, and exposes a near-passthrough HTTP forwarder. No re-signing needed here.@emulators/core'sWebhookDispatcheralready signs deliveries withX-Hub-Signature-256: sha256=<hex>exactly as the GitHub adapter expects. The harness also adds a small URL rewriter for Octokit'spulls.createReplyForReviewCommentshortcut endpoint, translating it into the canonical review-comment POST that the emulator implements.apiUrl+webhookSecretconfig zero source changes topackages/adapter-github:emulator-github-auth.test.ts(2)GET /userpopulatesbotUserIdduringinitialize().emulator-github-comments.test.ts(4)thread.post/edit/deleteon issue and PR-conversation threads.emulator-github-reviews.test.ts(3) review-comment replies routed throughpulls.createReplyForReviewCommentwith the right `in_reply_to_id`, plus edit / delete.emulator-github-events.test.ts(3) full inboundissue_comment/pull_request_review_commentround-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)"| SDKOut of scope (deliberate)
@emulators/githubdoes not implement the/reactionsendpoints used by the adapter. Reaction logic is still covered by the existing mock-based tests inpackages/adapter-github/src/index.test.ts.POST /app/installations/:id/access_tokens) the adapter and emulator both support it, but PAT-mode was the agreed scope here.installationwebhook events.Test plan
pnpm --filter @chat-adapter/integration-tests test407 tests pass across 34 files (including the 12 new emulator-github tests, ~480 ms total).pnpm checkandpnpm knipclean.port: 0), loopback-only binds (127.0.0.1), deterministic teardown viahttpServer.close(), no env vars, no external network egress.Checklist