test(channels): add behavior registration tests for the remaining channel fleet

discord, gchat, github, imessage, linear, matrix, resend, teams, telegram,
webex, whatsapp-cloud, signal, wechat, whatsapp, emacs.

Same behavior shape as the slack/deltachat exemplars: import the real
src/channels/index.ts barrel and assert getRegisteredChannelNames() contains
the channel. Red if the barrel import line is deleted/drifts, if the barrel
fails to evaluate, or (for channels with an npm adapter) if the adapter package
is not installed — so each test also implicitly guards the skill's dependency.
signal and emacs have no npm adapter (signal-cli binary / http builtin), so
their tests guard the single barrel reach-in only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-06-06 18:44:14 +03:00
parent 7ceb06cc8a
commit 8137440698
15 changed files with 490 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the discord channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs discord.ts's
* top-level `registerChannelAdapter('discord', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './discord.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and discord.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@chat-adapter/discord`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* discord is a Chat SDK channel: discord.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('discord channel registration', () => {
it('registers discord via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('discord');
});
});
+29
View File
@@ -0,0 +1,29 @@
/**
* Integration test for the emacs channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs emacs.ts's
* top-level `registerChannelAdapter('emacs', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './emacs.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* emacs is a native adapter with no npm dependency (it uses the Node http builtin); it talks to an Emacs HTTP client.
* Importing the barrel is safe: registration is a pure top-level call and emacs.ts
* opens connections / spawns subprocesses only inside setup() (run at host startup),
* never at import. There is no adapter package to guard here — this test guards the
* one barrel reach-in (red if `import './emacs.js';` is deleted or the barrel fails
* to evaluate).
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('emacs channel registration', () => {
it('registers emacs via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('emacs');
});
});
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the gchat channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs gchat.ts's
* top-level `registerChannelAdapter('gchat', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './gchat.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and gchat.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@chat-adapter/gchat`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* gchat is a Chat SDK channel: gchat.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('gchat channel registration', () => {
it('registers gchat via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('gchat');
});
});
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the github channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs github.ts's
* top-level `registerChannelAdapter('github', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './github.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and github.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@chat-adapter/github`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* github is a Chat SDK channel: github.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('github channel registration', () => {
it('registers github via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('github');
});
});
@@ -0,0 +1,34 @@
/**
* Integration test for the imessage channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs imessage.ts's
* top-level `registerChannelAdapter('imessage', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './imessage.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and imessage.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`chat-adapter-imessage`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* imessage is a Chat SDK channel: imessage.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('imessage channel registration', () => {
it('registers imessage via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('imessage');
});
});
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the linear channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs linear.ts's
* top-level `registerChannelAdapter('linear', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './linear.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and linear.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@chat-adapter/linear`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* linear is a Chat SDK channel: linear.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('linear channel registration', () => {
it('registers linear via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('linear');
});
});
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the matrix channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs matrix.ts's
* top-level `registerChannelAdapter('matrix', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './matrix.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and matrix.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@beeper/chat-adapter-matrix`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* matrix is a Chat SDK channel: matrix.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('matrix channel registration', () => {
it('registers matrix via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('matrix');
});
});
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the resend channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs resend.ts's
* top-level `registerChannelAdapter('resend', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './resend.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and resend.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@resend/chat-sdk-adapter`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* resend is a Chat SDK channel: resend.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('resend channel registration', () => {
it('registers resend via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('resend');
});
});
+29
View File
@@ -0,0 +1,29 @@
/**
* Integration test for the signal channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs signal.ts's
* top-level `registerChannelAdapter('signal', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './signal.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* signal is a native adapter with no npm dependency (it drives the external signal-cli binary over a local TCP socket); it talks to signal-cli.
* Importing the barrel is safe: registration is a pure top-level call and signal.ts
* opens connections / spawns subprocesses only inside setup() (run at host startup),
* never at import. There is no adapter package to guard here — this test guards the
* one barrel reach-in (red if `import './signal.js';` is deleted or the barrel fails
* to evaluate).
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('signal channel registration', () => {
it('registers signal via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('signal');
});
});
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the teams channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs teams.ts's
* top-level `registerChannelAdapter('teams', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './teams.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and teams.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@chat-adapter/teams`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* teams is a Chat SDK channel: teams.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('teams channel registration', () => {
it('registers teams via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('teams');
});
});
@@ -0,0 +1,34 @@
/**
* Integration test for the telegram channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs telegram.ts's
* top-level `registerChannelAdapter('telegram', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './telegram.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and telegram.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@chat-adapter/telegram`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* telegram is a Chat SDK channel: telegram.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('telegram channel registration', () => {
it('registers telegram via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('telegram');
});
});
+34
View File
@@ -0,0 +1,34 @@
/**
* Integration test for the webex channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs webex.ts's
* top-level `registerChannelAdapter('webex', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './webex.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and webex.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@bitbasti/chat-adapter-webex`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* webex is a Chat SDK channel: webex.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('webex channel registration', () => {
it('registers webex via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('webex');
});
});
+29
View File
@@ -0,0 +1,29 @@
/**
* Integration test for the wechat channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs wechat.ts's
* top-level `registerChannelAdapter('wechat', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './wechat.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* wechat is a native adapter (no Chat SDK bridge). Importing the barrel is safe:
* registration is a pure top-level call and wechat.ts opens connections / spawns
* subprocesses only inside setup() (run at host startup), never at import. It does
* require the adapter package (`wechat-ilink-client`) to be installed, which holds in a composed
* install: the skill's `pnpm install` step runs before this test — so this test also
* implicitly guards that dependency (an unmocked import throws if the package is missing).
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('wechat channel registration', () => {
it('registers wechat via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('wechat');
});
});
@@ -0,0 +1,34 @@
/**
* Integration test for the whatsapp-cloud channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs whatsapp-cloud.ts's
* top-level `registerChannelAdapter('whatsapp-cloud', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './whatsapp-cloud.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* Importing the barrel is safe: registration is a pure top-level call, and whatsapp-cloud.ts
* builds the SDK adapter / bridge only inside its factory (invoked at host startup),
* never at import. It does require the adapter package (`@chat-adapter/whatsapp`) to be installed,
* which holds in a composed install: the skill's `pnpm install` step runs before this
* test — so this test also implicitly guards that dependency (an unmocked import throws
* if the package is missing).
*
* whatsapp-cloud is a Chat SDK channel: whatsapp-cloud.ts also consumes a load-bearing *core* API —
* `createChatSdkBridge(...)` from ./chat-sdk-bridge.js. That core-consumption is a
* typed call, so the build/typecheck leg (`pnpm run build`) guards it against upstream
* drift, not this test. Every Chat SDK channel follows this same shape.
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('whatsapp-cloud channel registration', () => {
it('registers whatsapp-cloud via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('whatsapp-cloud');
});
});
@@ -0,0 +1,29 @@
/**
* Integration test for the whatsapp channel's single reach-in: the self-registration
* import in the `src/channels/index.ts` barrel. Importing the barrel runs whatsapp.ts's
* top-level `registerChannelAdapter('whatsapp', …)`; without the import the channel is
* silently absent.
*
* Behavior, not structural: it imports the real barrel and asserts the registry
* actually contains the channel. This reflects what happens at host boot — if the
* `import './whatsapp.js';` line is deleted, or the barrel fails to evaluate for any
* reason (so the channel genuinely would not register), this goes red. A structural
* check of the import line would falsely pass in that second case.
*
* whatsapp is a native adapter (no Chat SDK bridge). Importing the barrel is safe:
* registration is a pure top-level call and whatsapp.ts opens connections / spawns
* subprocesses only inside setup() (run at host startup), never at import. It does
* require the adapter package (`@whiskeysockets/baileys`) to be installed, which holds in a composed
* install: the skill's `pnpm install` step runs before this test — so this test also
* implicitly guards that dependency (an unmocked import throws if the package is missing).
*/
import { describe, it, expect } from 'vitest';
import { getRegisteredChannelNames } from './channel-registry.js';
import './index.js'; // the real barrel — triggers every channel's self-registration
describe('whatsapp channel registration', () => {
it('registers whatsapp via the channel barrel', () => {
expect(getRegisteredChannelNames()).toContain('whatsapp');
});
});