From 7a4281aaa9fdd213ba90427d1582ebbd4474a78f Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Tue, 24 Dec 2019 15:50:44 +0900 Subject: [PATCH] Fix #354 Add `client` to the list of args send through to listeners --- src/App.spec.ts | 48 ++++++++++++++++++++++++++++++++++ src/App.ts | 3 ++- src/middleware/builtin.spec.ts | 13 +++++++++ src/types/actions/index.ts | 2 ++ src/types/command/index.ts | 2 ++ src/types/events/index.ts | 2 ++ src/types/options/index.ts | 2 ++ src/types/view/index.ts | 2 ++ 8 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/App.spec.ts b/src/App.spec.ts index 2939d3080..5dc5a5fe3 100644 --- a/src/App.spec.ts +++ b/src/App.spec.ts @@ -662,6 +662,54 @@ describe('App', () => { }); }); + describe('client', () => { + + it('should be available in middleware/listener args', async () => { + // Arrange + const App = await importApp(mergeOverrides( // tslint:disable-line:variable-name + withNoopAppMetadata(), + withSuccessfulBotUserFetchingWebClient('B123', 'U123'), + )); + const app = new App({ + receiver: fakeReceiver, + authorize: sinon.fake.resolves(dummyAuthorizationResult), + }); + app.use(async ({ client }) => { + await client.auth.test(); + }); + app.event('app_home_opened', async ({ client }) => { + await client.auth.test(); + }); + + const receiverEvents = [ + { + body: { + type: 'event_callback', + token: 'XXYYZZ', + team_id: 'TXXXXXXXX', + api_app_id: 'AXXXXXXXXX', + event: { + type: 'app_home_opened', + event_ts: '1234567890.123456', + user: 'UXXXXXXX1', + text: 'hello friends!', + tab: 'home', + view: {}, + }, + }, + respond: noop, + ack: noop, + }, + ]; + + // Act + receiverEvents.forEach(event => fakeReceiver.emit('message', event)); + await delay(); + + // Assert + }); + }); + describe('say()', () => { function createChannelContextualReceiverEvents(channelId: string): ReceiverEvent[] { diff --git a/src/App.ts b/src/App.ts index 1dd4711cb..7f8c0eae4 100644 --- a/src/App.ts +++ b/src/App.ts @@ -430,7 +430,7 @@ export default class App { // Set body and payload (this value will eventually conform to AnyMiddlewareArgs) // NOTE: the following doesn't work because... distributive? // const listenerArgs: Partial = { - const listenerArgs: Pick & { + const listenerArgs: Pick & { /** Say function might be set below */ say?: SayFn /** Respond function might be set below */ @@ -439,6 +439,7 @@ export default class App { ack?: AckFn, } = { logger: this.logger, + client: this.client, body: bodyArg, payload: (type === IncomingEventType.Event) ? diff --git a/src/middleware/builtin.spec.ts b/src/middleware/builtin.spec.ts index be473d47c..1353ce8f3 100644 --- a/src/middleware/builtin.spec.ts +++ b/src/middleware/builtin.spec.ts @@ -16,6 +16,7 @@ import { import { onlyCommands, onlyEvents, matchCommandName, matchEventType, subtype } from './builtin'; import { SlashCommand } from '../types/command/index'; import { SlackEvent, AppMentionEvent, BotMessageEvent } from '../types/events/base-events'; +import { WebClient } from '@slack/web-api'; describe('matchMessage()', () => { function initializeTestCase(pattern: string | RegExp): Mocha.AsyncFunc { @@ -434,12 +435,14 @@ describe('ignoreSelf()', () => { describe('onlyCommands', () => { const logger = createFakeLogger(); + const client = new WebClient(undefined, { logger, slackApiUrl: undefined }); it('should detect valid requests', async () => { const payload: SlashCommand = { ...validCommandPayload }; const fakeNext = sinon.fake(); onlyCommands({ logger, + client, payload, command: payload, body: payload, @@ -457,6 +460,7 @@ describe('onlyCommands', () => { const fakeNext = sinon.fake(); onlyCommands({ logger, + client, payload, action: payload, command: undefined, @@ -473,11 +477,13 @@ describe('onlyCommands', () => { describe('matchCommandName', () => { const logger = createFakeLogger(); + const client = new WebClient(undefined, { logger, slackApiUrl: undefined }); function buildArgs(fakeNext: NextMiddleware): SlackCommandMiddlewareArgs & { next: any, context: any } { const payload: SlashCommand = { ...validCommandPayload }; return { logger, + client, payload, command: payload, body: payload, @@ -505,11 +511,13 @@ describe('matchCommandName', () => { describe('onlyEvents', () => { const logger = createFakeLogger(); + const client = new WebClient(undefined, { logger, slackApiUrl: undefined }); it('should detect valid requests', async () => { const fakeNext = sinon.fake(); const args: SlackEventMiddlewareArgs<'app_mention'> & { event?: SlackEvent } = { logger, + client, payload: appMentionEvent, event: appMentionEvent, message: null as never, // a bit hackey to sartisfy TS compiler @@ -534,6 +542,7 @@ describe('onlyEvents', () => { const fakeNext = sinon.fake(); onlyEvents({ logger, + client, payload, command: payload, body: payload, @@ -549,10 +558,12 @@ describe('onlyEvents', () => { describe('matchEventType', () => { const logger = createFakeLogger(); + const client = new WebClient(undefined, { logger, slackApiUrl: undefined }); function buildArgs(): SlackEventMiddlewareArgs<'app_mention'> & { event?: SlackEvent } { return { logger, + client, payload: appMentionEvent, event: appMentionEvent, message: null as never, // a bit hackey to sartisfy TS compiler @@ -585,10 +596,12 @@ describe('matchEventType', () => { describe('subtype', () => { const logger = createFakeLogger(); + const client = new WebClient(undefined, { logger, slackApiUrl: undefined }); function buildArgs(): SlackEventMiddlewareArgs<'message'> & { event?: SlackEvent } { return { logger, + client, payload: botMessageEvent, event: botMessageEvent, message: botMessageEvent, diff --git a/src/types/actions/index.ts b/src/types/actions/index.ts index 8e4016399..a89b9dee8 100644 --- a/src/types/actions/index.ts +++ b/src/types/actions/index.ts @@ -9,6 +9,7 @@ import { DialogSubmitAction, DialogValidation } from './dialog-action'; import { MessageAction } from './message-action'; import { SayFn, SayArguments, RespondFn, AckFn } from '../utilities'; import { Logger } from '@slack/logger'; +import { WebClient } from '@slack/web-api'; /** * All known actions from Slack's Block Kit interactive components, message actions, dialogs, and legacy interactive @@ -36,6 +37,7 @@ export type SlackAction = BlockAction | InteractiveMessage | DialogSubmitAction */ export interface SlackActionMiddlewareArgs { logger: Logger; + client: WebClient; payload: ( Action extends BlockAction ? ElementAction : Action extends InteractiveMessage ? InteractiveAction : diff --git a/src/types/command/index.ts b/src/types/command/index.ts index c06a0dfc4..9c6345eda 100644 --- a/src/types/command/index.ts +++ b/src/types/command/index.ts @@ -1,12 +1,14 @@ import { StringIndexed } from '../helpers'; import { SayFn, RespondFn, RespondArguments, AckFn } from '../utilities'; import { Logger } from '@slack/logger'; +import { WebClient } from '@slack/web-api'; /** * Arguments which listeners and middleware receive to process a slash command from Slack. */ export interface SlackCommandMiddlewareArgs { logger: Logger; + client: WebClient; payload: SlashCommand; command: this['payload']; body: this['payload']; diff --git a/src/types/events/index.ts b/src/types/events/index.ts index 381f64d8f..5857fff7a 100644 --- a/src/types/events/index.ts +++ b/src/types/events/index.ts @@ -3,12 +3,14 @@ import { SlackEvent, BasicSlackEvent } from './base-events'; import { StringIndexed } from '../helpers'; import { SayFn } from '../utilities'; import { Logger } from '@slack/logger'; +import { WebClient } from '@slack/web-api'; /** * Arguments which listeners and middleware receive to process an event from Slack's Events API. */ export interface SlackEventMiddlewareArgs { logger: Logger; + client: WebClient; payload: EventFromType; event: this['payload']; message: EventType extends 'message' ? this['payload'] : never; diff --git a/src/types/options/index.ts b/src/types/options/index.ts index 0cf36bacd..61cde6bc4 100644 --- a/src/types/options/index.ts +++ b/src/types/options/index.ts @@ -2,12 +2,14 @@ import { Option } from '@slack/types'; import { StringIndexed, XOR } from '../helpers'; import { AckFn } from '../utilities'; import { Logger } from '@slack/logger'; +import { WebClient } from '@slack/web-api'; /** * Arguments which listeners and middleware receive to process an options request from Slack */ export interface SlackOptionsMiddlewareArgs { logger: Logger; + client: WebClient; payload: OptionsRequest; body: this['payload']; options: this['payload']; diff --git a/src/types/view/index.ts b/src/types/view/index.ts index 49b5ee08c..26ff3ebd3 100644 --- a/src/types/view/index.ts +++ b/src/types/view/index.ts @@ -1,6 +1,7 @@ import { StringIndexed } from '../helpers'; import { RespondArguments, AckFn } from '../utilities'; import { Logger } from '@slack/logger'; +import { WebClient } from '@slack/web-api'; /** * Known view action types @@ -12,6 +13,7 @@ export type SlackViewAction = ViewSubmitAction | ViewClosedAction; */ export interface SlackViewMiddlewareArgs { logger: Logger; + client: WebClient; payload: ViewOutput; view: this['payload']; body: ViewActionType;