Testing Examples

The sample Apex SDK for Slack app contains an example implementation of the test harness.

These sections show sample app examples.

Test the Command Dispatcher 

This example creates an account record and views it in a modal. It runs a test for the ViewRecordCommandDispatcher.cls Apex action in the sample app.

1@isTest
2public class TestViewRecordCommandDispatcher {
3
4    private static Slack.App slackApp;
5    private static Slack.TestHarness testHarness;
6    private static Slack.TestHarness.State slackState;
7    private static Slack.TestHarness.UserSession userSession;
8
9    static {
10        // Set up test harness and user session
11        slackApp = Slack.App.ApexSlackApp.get();
12        testHarness = new Slack.TestHarness();
13        slackState = testHarness.getNewSlackState();
14        userSession = slackState.createUserSession();
15    }
16
17    // Create an account and view it in a modal
18    @isTest
19    static void testViewAccount() {
20
21        // Create new account record
22        Test.startTest();
23        Account account = new Account(Name='Bob');
24        insert account;
25        Test.stopTest();
26
27        // Execute the 'apex-view-record' command and assert modal
28        userSession.executeSlashCommand('/apex-view-record', 'Account ' + account.Id, slackApp);
29        Slack.TestHarness.Modal modal = userSession.getTopModal();
30        System.assertEquals('View Account', modal.getTitle());
31        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(1, Slack.TestHarness.Section.class);
32        System.assertEquals('Bob', section.getText());
33
34        modal.submit();
35
36        // Assert message contents with fields: name and id
37        List<Slack.TestHarness.Message> messages = userSession.getMessages();
38        System.assertEquals(1, messages.size());
39        Slack.TestHarness.Message message = messages.get(0);
40        System.assertEquals(4, message.getComponentCount());
41        Slack.TestHarness.Header header = (Slack.TestHarness.Header)message.getComponent(0, Slack.TestHarness.Header.class);
42        System.assertEquals('Account Record Details', header.getText());
43        Slack.TestHarness.Field field = (Slack.TestHarness.Field)message.getComponent(2, Slack.TestHarness.Field.class);
44        System.assertEquals('Name', field.getLabel());
45        System.assertEquals('Bob', field.getField());
46        field = (Slack.TestHarness.Field)message.getComponent(3, Slack.TestHarness.Field.class);
47        System.assertEquals('Id', field.getLabel());
48        System.assertEquals(account.Id, field.getField());
49
50    }
51
52    // Create a contact and view it in a modal
53    @isTest
54    static void testViewContact() {
55
56        // Create new account and contact records
57        Test.startTest();
58        Account account = new Account(Name='Joe Co');
59        insert account;
60        Contact contact = new Contact(
61            FirstName='Joe',
62            LastName='Smith',
63            Phone='777-777-7777',
64            Email='joesmith@example.com',
65            AccountId=account.Id
66        );
67        insert contact;
68        Test.stopTest();
69
70        // Execute the 'apex-view-record' command and assert modal
71        userSession.executeSlashCommand('/apex-view-record', 'Contact ' + contact.Id, slackApp);
72        Slack.TestHarness.Modal modal = userSession.getTopModal();
73        System.assertEquals('View Contact', modal.getTitle());
74        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(1, Slack.TestHarness.Section.class);
75        System.assertEquals('Joe Smith', section.getText());
76
77        modal.submit();
78
79        // Assert message contents with fields: name, id, phone, and email
80        List<Slack.TestHarness.Message> messages = userSession.getMessages();
81        System.assertEquals(1, messages.size());
82        Slack.TestHarness.Message message = messages.get(0);
83        System.assertEquals(6, message.getComponentCount());
84        Slack.TestHarness.Header header = (Slack.TestHarness.Header)message.getComponent(0, Slack.TestHarness.Header.class);
85        System.assertEquals('Contact Record Details', header.getText());
86        Slack.TestHarness.Field field = (Slack.TestHarness.Field)message.getComponent(2, Slack.TestHarness.Field.class);
87        System.assertEquals('Name', field.getLabel());
88        System.assertEquals('Joe Smith', field.getField());
89        field = (Slack.TestHarness.Field)message.getComponent(3, Slack.TestHarness.Field.class);
90        System.assertEquals('Id', field.getLabel());
91        System.assertEquals(contact.Id, field.getField());
92        field = (Slack.TestHarness.Field)message.getComponent(4, Slack.TestHarness.Field.class);
93        System.assertEquals('Phone', field.getLabel());
94        System.assertEquals('777-777-7777', field.getField());
95        field = (Slack.TestHarness.Field)message.getComponent(5, Slack.TestHarness.Field.class);
96        System.assertEquals('Email', field.getLabel());
97        System.assertEquals('joesmith@example.com', field.getField());
98
99    }
100
101    // Create an opportunity and view it in a modal
102    @isTest
103    static void testViewOpportunity() {
104
105        // Create new opportunity record
106        Test.startTest();
107        Opportunity opportunity = new Opportunity(
108            Name='Acme Co.',
109            Amount=50000.00,
110            StageName='Qualification',
111            CloseDate=Date.valueOf('2222-12-31')
112        );
113        insert opportunity;
114        Test.stopTest();
115
116        // Execute the 'apex-view-record' command and assert modal
117        userSession.executeSlashCommand('/apex-view-record', 'Opportunity ' + opportunity.Id, slackApp);
118        Slack.TestHarness.Modal modal = userSession.getTopModal();
119        System.assertEquals('View Opportunity', modal.getTitle());
120        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(1, Slack.TestHarness.Section.class);
121        System.assertEquals('Acme Co.', section.getText());
122
123        modal.submit();
124
125        // Assert message contents with fields: name, id, amount, stage name, qualification, and close date
126        List<Slack.TestHarness.Message> messages = userSession.getMessages();
127        System.assertEquals(1, messages.size());
128        Slack.TestHarness.Message message = messages.get(0);
129        System.assertEquals(7, message.getComponentCount());
130        Slack.TestHarness.Header header = (Slack.TestHarness.Header)message.getComponent(0, Slack.TestHarness.Header.class);
131        System.assertEquals('Opportunity Record Details', header.getText());
132        Slack.TestHarness.Field field = (Slack.TestHarness.Field)message.getComponent(2, Slack.TestHarness.Field.class);
133        System.assertEquals('Name', field.getLabel());
134        System.assertEquals('Acme Co.', field.getField());
135        field = (Slack.TestHarness.Field)message.getComponent(3, Slack.TestHarness.Field.class);
136        System.assertEquals('Id', field.getLabel());
137        System.assertEquals(opportunity.Id, field.getField());
138        field = (Slack.TestHarness.Field)message.getComponent(4, Slack.TestHarness.Field.class);
139        System.assertEquals('Amount', field.getLabel());
140        System.assertEquals('50000.00', field.getField());
141        field = (Slack.TestHarness.Field)message.getComponent(5, Slack.TestHarness.Field.class);
142        System.assertEquals('StageName', field.getLabel());
143        System.assertEquals('Qualification', field.getField());
144        field = (Slack.TestHarness.Field)message.getComponent(6, Slack.TestHarness.Field.class);
145        System.assertEquals('CloseDate', field.getLabel());
146        System.assertEquals('Tue Dec 31 00:00:00 GMT 2222', field.getField());
147    }
148
149    // Run the view record command without any parameters
150    @isTest
151    static void testMissingParams() {
152
153        // Execute the 'apex-view-record' command without parameters
154        userSession.executeSlashCommand('/apex-view-record', slackApp);
155
156        // Assert the message modal
157        Slack.TestHarness.Modal modal = userSession.getTopModal();
158        System.assertEquals('Invalid Parameters', modal.getTitle());
159        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(0, Slack.TestHarness.Section.class);
160        System.assertEquals('The view record command requires 2 arguments: objectApiName and recordId.', section.getText());
161
162    }
163
164    // Run the view record command with invalid parameters
165    @isTest
166    static void testInvalidObject() {
167
168        // Execute the 'apex-view-record' command with an invalid object
169        userSession.executeSlashCommand('/apex-view-record', 'Invalid_Object Invalid_Record_Id', slackApp);
170
171        // Assert the message modal
172        Slack.TestHarness.Modal modal = userSession.getTopModal();
173        System.assertEquals('Invalid Object', modal.getTitle());
174        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(0, Slack.TestHarness.Section.class);
175        System.assertEquals('The objectApiName was not a valid option. The view record command supports Account, Contact, and Opportunity', section.getText());
176
177    }
178
179}

Mock the Bot Client using the Test Harness 

For these examples, assume that a basic test harness is set up and the methods are implemented as part of a Slack.BotClientMock.

Basic Setup 

This example test suite shows how to mock methods by using the test harness.

1@isTest
2public class MyBasicTestSuite {
3
4    private static Slack.App slackApp;
5    private static Slack.TestHarness testHarness;
6    private static Slack.TestHarness.State slackState;
7    private static Slack.TestHarness.UserSession userSession;
8
9    static {
10        // setup test harness and user session
11        slackApp = Slack.App.ApexSlackApp.get();
12        testHarness = new Slack.TestHarness();
13        slackState = testHarness.getNewSlackState();
14        userSession = slackState.createUserSession();
15    }
16
17    @isTest
18    static void basicTest() {
19        // set the client mock
20        slackState.setBotClientMock(new BasicClientMock());
21
22        // perform test operations such as calling slash commands,
23        // shortcuts, or invoking events
24
25        // clear the client mock
26        slackState.clearBotClientMock();
27    }
28
29    // BotClientMock implementation for testing
30    class BasicClientMock extends Slack.BotClientMock {
31        // method overrides
32    }
33
34}

ConversationsCreate 

This example overwrites the bot clients conversationsCreate method. It requires a single Slack.ConversationsCreateRequest object as a parameter and returns a Slack.ConversationsCreateResponse object as the result. In this example, the Slack state is established in the test context to create a channel using the name from the request object. A successful response is returned with the new channel id and name.

See the Slack Documentation for more information on the conversations.create request and response objects.

1public override Slack.ConversationsCreateResponse conversationsCreate(Slack.ConversationsCreateRequest request) {
2    Slack.TestHarness.Channel newChannel = null;
3    if (request.isPrivate()) {
4       newChannel = slackState.createPrivateChannel(request.getName());
5    } else {
6        newChannel = slackState.createPublicChannel(request.getName());
7    }
8   Slack.ConversationsCreateResponse response = new Slack.ConversationsCreateResponse();
9    response.setOk(true);
10    Slack.Conversation conversation = new Slack.Conversation();
11    conversation.setId(newChannel.getId());
12    conversation.setName(newChannel.getName());
13    response.setChannel(conversation);
14    return response;
15}

Conversations Invite 

This example overwrites the bot clients conversationsInvite method. It requires a single Slack.ConversationsInviteRequest object as a parameter and returns a Slack.ConversationsInviteResponse object as the result. In this example, the Slack state and the default team are established in the test context to invite the users specified in the request object to the designated channel. A successful response is returned.

See the Slack Documentation for more information on the conversations.invite request and response objects.

Orgs need to be on Spring ‘23 to use the getters associated with any request object.

Note

1public override Slack.ConversationsInviteResponse conversationsInvite(Slack.ConversationsInviteRequest request) {
2    Slack.TestHarness.Team team = slackState.getDefaultTeam();
3    String channelId = request.getChannel();
4    Slack.TestHarness.Channel channel = slackState.getChannel(team, channelId);
5    for (String userId: request.getUsers()) {
6        channel.addUser(slackState.getUser(team, userId));
7    }
8    Slack.ConversationsInviteResponse response = new Slack.ConversationsInviteResponse();
9    response.setOk(true);
10    return response;
11}

ConversationsList 

This example overwrites the bot clients conversationsList method. It requires a single Slack.ConversationsListRequest object as a parameter and returns a Slack.ConversationsListResponse object as the result. In this example, the Slack state and default team are established in the test context to return the list of channels. A successful response is returned with a list of channels.

See the Slack Documentation for more information on the conversations.list request and response objects.

1public override Slack.ConversationsListResponse conversationsList(Slack.ConversationsListRequest request) {
2        List<Slack.Conversation> conversations = new List<Slack.Conversation>();
3       List<Slack.TestHarness.Channel> channels = slackState.getDefaultTeam().getChannels();
4        for (Slack.TestHarness.Channel channel: channels) {
5            Slack.Conversation conversation = new Slack.Conversation();
6            conversation.setId(channel.getId());
7            conversation.setName(channel.getName());
8            conversations.add(conversation);
9        }
10        Slack.ConversationsListResponse response = new Slack.ConversationsListResponse();
11        response.setOk(true);
12        response.setChannels(conversations);
13        return response;
14    }

ConversationsInfo 

This example overwrites the bot clients conversationsInfo method. It requires a single Slack.ConversationsInfoRequest object as a parameter and returns a Slack.ConversationsInfoResponse object as the result. In this example, the super method is called to get information about the requested channel. The mocked topic value is added to the successful response. See the Slack Documentation for more information on the conversations.info request and response objects.

1public override Slack.ConversationsInfoResponse conversationsInfo(Slack.ConversationsInfoRequest request) {
2    Slack.ConversationsInfoResponse response = super.conversationsInfo(request);
3    Slack.Conversation conversation = response.getChannel();
4    Slack.Topic topic = new Slack.Topic();
5    topic.setValue('Mock Topic Value');
6    conversation.setTopic(topic);
7    response.setChannel(conversation);
8    return response;
9}

Pins Add 

This example overwrites the bot clients pinsAdd method. It requires a single Slack.PinsAddRequest object as a parameter and returns a Slack.PinsAddResponse object as the result. In this example, the pin information from the request is added to a map that can be used to retrieve the information in a future request. When the request is made it’s followed by returning a successful response. See the Slack Documentation for more information on the pins.add request and response objects.

1Map<String, List<String>> pins = new Map<String, List<String>>();
2
3public override Slack.PinsAddResponse pinsAdd(Slack.PinsAddRequest request) {
4    String channelId = request.getChannel();
5    String timestamp = request.getTimestamp();
6    if (!pins.containsKey(channelId)) {
7        pins.put(channelId, new List<String>());
8    }
9    if (!pins.get(channelId).contains(timestamp)) {
10        pins.get(channelId).add(timestamp);
11    }
12    Slack.PinsAddResponse response = new Slack.PinsAddResponse();
13    response.setOk(true);
14    return response;
15}

Pins List 

This example overwrites the bot clients pinsList method. It requires a single Slack.PinsListRequest object as a parameter and returns a Slack.PinsListResponse object as the result. In this example, the pin information for the given channel specified in the request is removed and a successful response is returned with the list of pinned items. See the Slack Documentation for more information on the pins.list request and response objects.

1Map<String, List<String>> pins = new Map<String, List<String>>();
2
3public override Slack.PinsListResponse pinsList(Slack.PinsListRequest request) {
4    String channelId = request.getChannel();
5    Slack.TestHarness.Channel channel = slackState.getChannel(slackState.getDefaultTeam(), channelId);
6    if (!pins.containsKey(channelId)) {
7        pins.put(channelId, new List<String>());
8    }
9    List<Slack.PinsListResponse.MessageItem> items = new List<Slack.PinsListResponse.MessageItem>();
10    for (String pinTs: pins.get(channelId)) {
11        Slack.PinsListResponse.MessageItem item = new Slack.PinsListResponse.MessageItem();
12        item.setChannel(channelId);
13        item.setType('message');
14        items.add(item);
15    }
16    Slack.PinsListResponse response = new Slack.PinsListResponse();
17    response.setOk(true);
18    response.setItems(items);
19    return response;
20}

PinRemove 

This example overwrites the bot clients pinsRemove method. It requires a single Slack.PinsRemoveRequest object as a parameter and returns a Slack.PinsRemoveResponse object as the result. In this example, the pin information specified in the request is removed from the map containing the information and returned a successful response.
See the Slack Documentation for more information on the pins.remove request and response objects.

1Map<String, List<String>> pins = new Map<String, List<String>>();
2
3public override Slack.PinsRemoveResponse pinsRemove(Slack.PinsRemoveRequest request) {
4    String channelId = request.getChannel();
5    String timestamp = request.getTimestamp();
6    if (pins.containsKey(channelId) && pins.get(channelId).contains(timestamp)) {
7        pins.get(channelId).remove(pins.get(channelId).indexOf(timestamp));
8    }
9    Slack.PinsRemoveResponse response = new Slack.PinsRemoveResponse();
10    response.setOk(true);
11    return response;
12}

Beta Feature

This feature is not generally available. It is not part of your purchased Services. This feature is subject to change, may be discontinued with no notice at any time in SFDC’s sole discretion, and SFDC may never make this feature generally available. Make your purchase decisions only on the basis of generally available products and features. This feature is made available on an AS IS basis and use of this feature is at your sole risk.