Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 2s
183 lines
12 KiB
Markdown
183 lines
12 KiB
Markdown
# SlackBridge Manual Test Plan
|
|
|
|
The SlackBridge is a bi-directional bridge between a Rocket.Chat workspace and one or more Slack
|
|
workspaces — each token line in the SlackBridge settings gets its own connection and adapter. It
|
|
has no automated end-to-end coverage: exercising it requires a real Slack workspace, a real bot
|
|
installation, and a human watching both sides at once. This document is the checklist to walk
|
|
through when touching the bridge.
|
|
|
|
**Scope:** the matrices below assume a **single** bridged Slack workspace — configure exactly one
|
|
token per setting while running them. Bridging several workspaces at once is a supported
|
|
configuration that this plan does not cover; see [Coverage gaps](#coverage-gaps).
|
|
|
|
Code lives in [apps/meteor/server/bridges/slack/](../../apps/meteor/server/bridges/slack/) —
|
|
`SlackAdapter.ts` handles Slack → Rocket.Chat, `RocketAdapter.ts` handles Rocket.Chat → Slack
|
|
(hooked in through the `afterSaveMessage`, `afterDeleteMessage`, `afterSetReaction` and
|
|
`afterUnsetReaction` callbacks). Settings are declared in
|
|
[apps/meteor/server/settings/slackbridge.ts](../../apps/meteor/server/settings/slackbridge.ts).
|
|
|
|
## Setup
|
|
|
|
Configure the bridge in **Admin → Settings → SlackBridge**:
|
|
|
|
| Setting | Notes |
|
|
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
| `SlackBridge_Enabled` | Master switch. Must be on. |
|
|
| `SlackBridge_UseLegacy` | Chooses the connection mode — see below. Run the matrices in the mode you are testing. |
|
|
| `SlackBridge_APIToken` | Legacy mode only (RTM). |
|
|
| `SlackBridge_BotToken`, `SlackBridge_SigningSecret`, `SlackBridge_AppToken` | App mode only (Bolt / Socket Mode). |
|
|
| `SlackBridge_Out_Enabled` | Required for anything to flow Rocket.Chat → Slack. |
|
|
| `SlackBridge_Out_All` / `SlackBridge_Out_Channels` | Which Rocket.Chat rooms are bridged out. |
|
|
| `SlackBridge_Reactions_Enabled` | Gates reaction propagation in both directions. |
|
|
| `SlackBridge_AliasFormat` | Optional, Slack → Rocket.Chat only. `%s` is the Slack username; test with `%s (via Slack)`. |
|
|
| `SlackBridge_FileUpload_Enabled` | Gates file transfer. |
|
|
|
|
Two connection modes exist and they use different Slack event plumbing, so a regression can
|
|
appear in one and not the other. **Run the full matrix in both** when changing anything in the
|
|
connect/event-subscription path:
|
|
|
|
- **Legacy (`SlackBridge_UseLegacy: true`)** — RTM connection with an API token.
|
|
- **App (`SlackBridge_UseLegacy: false`)** — Slack app using bot token, signing secret and app
|
|
token.
|
|
|
|
You also need:
|
|
|
|
- A Slack workspace where you can create channels and install/invite the bot (referred to below
|
|
as **rocketbot**).
|
|
- At least one channel that exists on both sides **with** rocketbot in it, and one that exists on
|
|
both sides **without** rocketbot in it. Several cases below hinge on that difference.
|
|
- A second Slack user, if possible — some behaviors only show up when the message author is not
|
|
the same account as the bot.
|
|
|
|
Watch `SlackBridge` logs (`slackLogger` / `rocketLogger`) while testing; several expected
|
|
failures are only visible there.
|
|
|
|
## How to read the matrices
|
|
|
|
- **Origin** — where the message being acted on was originally posted.
|
|
- **Action performed on** — the side where the tester performs the action.
|
|
- Every matrix must also be repeated **on a channel that rocketbot is not a member of**. Nothing
|
|
should propagate in either direction for those channels, and nothing should error.
|
|
|
|
## Sending messages
|
|
|
|
| # | Origin | Action performed on | Expected result |
|
|
| --- | ----------- | ------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
| 1 | Slack | Slack | Message appears in the linked Rocket.Chat room, under the alias `SlackBridge_AliasFormat` produces. |
|
|
| 2 | Rocket.Chat | Rocket.Chat | Message appears in the linked Slack channel, posted by rocketbot with the sender's username and avatar. |
|
|
|
|
`SlackBridge_AliasFormat` only affects case 1: `addAliasToMsg` sets `alias` on the **Rocket.Chat**
|
|
message, so with `%s (via Slack)` a message from Slack user `alice` shows as `alice (via Slack)`.
|
|
Case 2 carries the sender's identity through `chat.postMessage`'s `username`/`icon_url` and ignores
|
|
the setting entirely. Set the format, run case 1 with it set and again with it empty, then **restore
|
|
the original value** before moving on — the later matrices assume the workspace's normal setup.
|
|
|
|
Repeat both on a channel without rocketbot: neither message crosses over.
|
|
|
|
## Editing messages
|
|
|
|
Slack does not allow an app to edit messages it did not post, and it does not allow humans to
|
|
edit bot messages. Two of the four cases are therefore **expected failures** — they are listed
|
|
because "nothing crashes and the local side stays consistent" is the requirement.
|
|
|
|
| # | Origin | Action performed on | Expected result |
|
|
| --- | ----------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| 1 | Slack | Slack | Edit propagates to Rocket.Chat. |
|
|
| 2 | Rocket.Chat | Rocket.Chat | Edit propagates to Slack. |
|
|
| 3 | Slack | Rocket.Chat | **Expected failure.** Rocket.Chat shows the edit; Slack is unchanged. `chat.update` is rejected because the message is not the bot's. |
|
|
| 4 | Rocket.Chat | Slack | **Expected failure.** Slack does not even offer the edit affordance for a bot message. |
|
|
|
|
Repeat on a channel without rocketbot: edits stay local on both sides.
|
|
|
|
## Deleting messages
|
|
|
|
Case 3 needs care about _who_ deletes. A Rocket.Chat-origin message is authored on Slack by
|
|
rocketbot, and Slack offers no delete affordance for an app's message to a regular member, so
|
|
pick one of:
|
|
|
|
- Delete it from the Slack UI as a **workspace owner or admin** — they can delete any message,
|
|
including an app's.
|
|
- Call `chat.delete` with the very token the bridge is configured with, so the caller is
|
|
rocketbot itself: `SlackBridge_APIToken` in legacy/RTM mode, `SlackBridge_BotToken` in
|
|
app/Socket Mode. Any other token fails with `cant_delete_message`, which is case 4's failure,
|
|
not case 3's.
|
|
|
|
Both routes emit the same `message_deleted` event, so either is a valid way to run the case.
|
|
|
|
| # | Origin | Action performed on | Expected result |
|
|
| --- | ----------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| 1 | Slack | Slack | Deletion propagates to Rocket.Chat. |
|
|
| 2 | Rocket.Chat | Rocket.Chat | Deletion propagates to Slack. |
|
|
| 3 | Rocket.Chat | Slack | Deletion propagates to Rocket.Chat — deleted as a workspace admin or via `chat.delete` with rocketbot's own token, per the note above. |
|
|
| 4 | Slack | Rocket.Chat | **Expected failure.** The message is deleted in Rocket.Chat only; Slack keeps it, since `chat.delete` cannot remove another user's message. |
|
|
|
|
Repeat on a channel without rocketbot: deletions stay local on both sides.
|
|
|
|
## Reactions
|
|
|
|
Requires `SlackBridge_Reactions_Enabled`. Reactions sent to Slack are added by the bot account,
|
|
so on the Slack side every Rocket.Chat reaction shows up as rocketbot's reaction regardless of
|
|
who actually reacted.
|
|
|
|
| # | Origin | Action performed on | Expected result |
|
|
| --- | ----------- | ------------------- | ----------------------------------------------------- |
|
|
| 1 | Slack | Slack | Reaction appears on the Rocket.Chat message. |
|
|
| 2 | Rocket.Chat | Slack | Reaction appears on the Rocket.Chat message. |
|
|
| 3 | Rocket.Chat | Rocket.Chat | Reaction appears on the Slack message (as rocketbot). |
|
|
| 4 | Slack | Rocket.Chat | Reaction appears on the Slack message (as rocketbot). |
|
|
|
|
Also check removal of each reaction, and confirm a reaction is not echoed back to its origin
|
|
(the bridge de-duplicates through its reactions map — a double-count means that broke).
|
|
|
|
Repeat on a channel without rocketbot: reactions stay local.
|
|
|
|
### `SlackBridge_Reactions_Enabled` toggle
|
|
|
|
| Setting state | Expected result |
|
|
| ------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
| Disabled | React to both a Slack-origin and a Rocket.Chat-origin message from both sides — nothing propagates, no errors. |
|
|
| Enabled | Re-run the same reactions — they propagate as in the matrix above, without restarting the server. |
|
|
|
|
## Channel lifecycle
|
|
|
|
These cases cover how the bridge reacts to channels appearing, disappearing, and the bot joining
|
|
or leaving. Send a message **from each side** after every step and verify propagation.
|
|
|
|
### Channel exists on both sides, rocketbot not in the Slack channel
|
|
|
|
1. Confirm nothing propagates in either direction.
|
|
2. Invite rocketbot to the Slack channel.
|
|
3. Send from Slack and from Rocket.Chat — both directions now work.
|
|
|
|
### Channel exists on Rocket.Chat only
|
|
|
|
1. Create the matching channel in Slack and invite rocketbot.
|
|
2. Send from Rocket.Chat — it reaches Slack.
|
|
3. Send from Slack — it reaches Rocket.Chat.
|
|
|
|
### Channel exists on Slack only
|
|
|
|
1. Invite rocketbot to the Slack channel.
|
|
2. Send from Slack — the Rocket.Chat channel is created and receives the message.
|
|
3. Send from Rocket.Chat — it reaches Slack.
|
|
|
|
### Channel exists on both sides with rocketbot
|
|
|
|
1. Delete the Rocket.Chat channel, then send from Slack — behaves like the "Slack only" case
|
|
above (the channel is recreated).
|
|
2. Remove rocketbot from the Slack channel, then send from Slack and from Rocket.Chat — nothing
|
|
propagates in either direction, and no errors are logged.
|
|
|
|
## Coverage gaps
|
|
|
|
The matrices above are the historical manual suite and deliberately mirror it. They do **not**
|
|
cover, and it is worth checking manually when relevant:
|
|
|
|
- File uploads (`SlackBridge_FileUpload_Enabled`).
|
|
- Slack history import (`/slackbridge-import`, `slackbridge_import.server.ts`).
|
|
- Threads (`thread_ts` mapping in `postMessage`).
|
|
- Private channels and DMs.
|
|
- `SlackBridge_ExcludeBotnames` filtering.
|
|
- The **Remove Channel Links** admin action (`SlackBridge_Remove_Channel_Links`).
|
|
- Multiple Slack workspaces bridged at once (one token per line in each token setting).
|