# Testing Examples

The [sample Apex SDK for Slack app](/docs/platform/salesforce-slack-sdk/guide/setup-install-app.md) 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](/docs/platform/salesforce-slack-sdk/guide/setup-install-app.md).

```java
@isTest
public class TestViewRecordCommandDispatcher {

    private static Slack.App slackApp;
    private static Slack.TestHarness testHarness;
    private static Slack.TestHarness.State slackState;
    private static Slack.TestHarness.UserSession userSession;

    static {
        // Set up test harness and user session
        slackApp = Slack.App.ApexSlackApp.get();
        testHarness = new Slack.TestHarness();
        slackState = testHarness.getNewSlackState();
        userSession = slackState.createUserSession();
    }

    // Create an account and view it in a modal
    @isTest
    static void testViewAccount() {

        // Create new account record
        Test.startTest();
        Account account = new Account(Name='Bob');
        insert account;
        Test.stopTest();

        // Execute the 'apex-view-record' command and assert modal
        userSession.executeSlashCommand('/apex-view-record', 'Account ' + account.Id, slackApp);
        Slack.TestHarness.Modal modal = userSession.getTopModal();
        System.assertEquals('View Account', modal.getTitle());
        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(1, Slack.TestHarness.Section.class);
        System.assertEquals('Bob', section.getText());

        modal.submit();

        // Assert message contents with fields: name and id
        List<Slack.TestHarness.Message> messages = userSession.getMessages();
        System.assertEquals(1, messages.size());
        Slack.TestHarness.Message message = messages.get(0);
        System.assertEquals(4, message.getComponentCount());
        Slack.TestHarness.Header header = (Slack.TestHarness.Header)message.getComponent(0, Slack.TestHarness.Header.class);
        System.assertEquals('Account Record Details', header.getText());
        Slack.TestHarness.Field field = (Slack.TestHarness.Field)message.getComponent(2, Slack.TestHarness.Field.class);
        System.assertEquals('Name', field.getLabel());
        System.assertEquals('Bob', field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(3, Slack.TestHarness.Field.class);
        System.assertEquals('Id', field.getLabel());
        System.assertEquals(account.Id, field.getField());

    }

    // Create a contact and view it in a modal
    @isTest
    static void testViewContact() {

        // Create new account and contact records
        Test.startTest();
        Account account = new Account(Name='Joe Co');
        insert account;
        Contact contact = new Contact(
            FirstName='Joe',
            LastName='Smith',
            Phone='777-777-7777',
            Email='joesmith@example.com',
            AccountId=account.Id
        );
        insert contact;
        Test.stopTest();

        // Execute the 'apex-view-record' command and assert modal
        userSession.executeSlashCommand('/apex-view-record', 'Contact ' + contact.Id, slackApp);
        Slack.TestHarness.Modal modal = userSession.getTopModal();
        System.assertEquals('View Contact', modal.getTitle());
        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(1, Slack.TestHarness.Section.class);
        System.assertEquals('Joe Smith', section.getText());

        modal.submit();

        // Assert message contents with fields: name, id, phone, and email
        List<Slack.TestHarness.Message> messages = userSession.getMessages();
        System.assertEquals(1, messages.size());
        Slack.TestHarness.Message message = messages.get(0);
        System.assertEquals(6, message.getComponentCount());
        Slack.TestHarness.Header header = (Slack.TestHarness.Header)message.getComponent(0, Slack.TestHarness.Header.class);
        System.assertEquals('Contact Record Details', header.getText());
        Slack.TestHarness.Field field = (Slack.TestHarness.Field)message.getComponent(2, Slack.TestHarness.Field.class);
        System.assertEquals('Name', field.getLabel());
        System.assertEquals('Joe Smith', field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(3, Slack.TestHarness.Field.class);
        System.assertEquals('Id', field.getLabel());
        System.assertEquals(contact.Id, field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(4, Slack.TestHarness.Field.class);
        System.assertEquals('Phone', field.getLabel());
        System.assertEquals('777-777-7777', field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(5, Slack.TestHarness.Field.class);
        System.assertEquals('Email', field.getLabel());
        System.assertEquals('joesmith@example.com', field.getField());

    }

    // Create an opportunity and view it in a modal
    @isTest
    static void testViewOpportunity() {

        // Create new opportunity record
        Test.startTest();
        Opportunity opportunity = new Opportunity(
            Name='Acme Co.',
            Amount=50000.00,
            StageName='Qualification',
            CloseDate=Date.valueOf('2222-12-31')
        );
        insert opportunity;
        Test.stopTest();

        // Execute the 'apex-view-record' command and assert modal
        userSession.executeSlashCommand('/apex-view-record', 'Opportunity ' + opportunity.Id, slackApp);
        Slack.TestHarness.Modal modal = userSession.getTopModal();
        System.assertEquals('View Opportunity', modal.getTitle());
        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(1, Slack.TestHarness.Section.class);
        System.assertEquals('Acme Co.', section.getText());

        modal.submit();

        // Assert message contents with fields: name, id, amount, stage name, qualification, and close date
        List<Slack.TestHarness.Message> messages = userSession.getMessages();
        System.assertEquals(1, messages.size());
        Slack.TestHarness.Message message = messages.get(0);
        System.assertEquals(7, message.getComponentCount());
        Slack.TestHarness.Header header = (Slack.TestHarness.Header)message.getComponent(0, Slack.TestHarness.Header.class);
        System.assertEquals('Opportunity Record Details', header.getText());
        Slack.TestHarness.Field field = (Slack.TestHarness.Field)message.getComponent(2, Slack.TestHarness.Field.class);
        System.assertEquals('Name', field.getLabel());
        System.assertEquals('Acme Co.', field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(3, Slack.TestHarness.Field.class);
        System.assertEquals('Id', field.getLabel());
        System.assertEquals(opportunity.Id, field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(4, Slack.TestHarness.Field.class);
        System.assertEquals('Amount', field.getLabel());
        System.assertEquals('50000.00', field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(5, Slack.TestHarness.Field.class);
        System.assertEquals('StageName', field.getLabel());
        System.assertEquals('Qualification', field.getField());
        field = (Slack.TestHarness.Field)message.getComponent(6, Slack.TestHarness.Field.class);
        System.assertEquals('CloseDate', field.getLabel());
        System.assertEquals('Tue Dec 31 00:00:00 GMT 2222', field.getField());
    }

    // Run the view record command without any parameters
    @isTest
    static void testMissingParams() {

        // Execute the 'apex-view-record' command without parameters
        userSession.executeSlashCommand('/apex-view-record', slackApp);

        // Assert the message modal
        Slack.TestHarness.Modal modal = userSession.getTopModal();
        System.assertEquals('Invalid Parameters', modal.getTitle());
        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(0, Slack.TestHarness.Section.class);
        System.assertEquals('The view record command requires 2 arguments: objectApiName and recordId.', section.getText());

    }

    // Run the view record command with invalid parameters
    @isTest
    static void testInvalidObject() {

        // Execute the 'apex-view-record' command with an invalid object
        userSession.executeSlashCommand('/apex-view-record', 'Invalid_Object Invalid_Record_Id', slackApp);

        // Assert the message modal
        Slack.TestHarness.Modal modal = userSession.getTopModal();
        System.assertEquals('Invalid Object', modal.getTitle());
        Slack.TestHarness.Section section = (Slack.TestHarness.Section)modal.getComponent(0, Slack.TestHarness.Section.class);
        System.assertEquals('The objectApiName was not a valid option. The view record command supports Account, Contact, and Opportunity', section.getText());

    }

}
```

## 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.

```java
@isTest
public class MyBasicTestSuite {

    private static Slack.App slackApp;
    private static Slack.TestHarness testHarness;
    private static Slack.TestHarness.State slackState;
    private static Slack.TestHarness.UserSession userSession;

    static {
        // setup test harness and user session
        slackApp = Slack.App.ApexSlackApp.get();
        testHarness = new Slack.TestHarness();
        slackState = testHarness.getNewSlackState();
        userSession = slackState.createUserSession();
    }

    @isTest
    static void basicTest() {
        // set the client mock
        slackState.setBotClientMock(new BasicClientMock());

        // perform test operations such as calling slash commands,
        // shortcuts, or invoking events

        // clear the client mock
        slackState.clearBotClientMock();
    }

    // BotClientMock implementation for testing
    class BasicClientMock extends Slack.BotClientMock {
        // method overrides
    }

}
```

## 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](https://api.slack.com/methods/conversations.create) for more information on the `conversations.create` request and response objects.

```java
public override Slack.ConversationsCreateResponse conversationsCreate(Slack.ConversationsCreateRequest request) {
    Slack.TestHarness.Channel newChannel = null;
    if (request.isPrivate()) {
       newChannel = slackState.createPrivateChannel(request.getName());
    } else {
        newChannel = slackState.createPublicChannel(request.getName());
    }
   Slack.ConversationsCreateResponse response = new Slack.ConversationsCreateResponse();
    response.setOk(true);
    Slack.Conversation conversation = new Slack.Conversation();
    conversation.setId(newChannel.getId());
    conversation.setName(newChannel.getName());
    response.setChannel(conversation);
    return response;
}
```

## 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](https://api.slack.com/methods/conversations.invite) for more information on the conversations.invite request and response objects.

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

```java
public override Slack.ConversationsInviteResponse conversationsInvite(Slack.ConversationsInviteRequest request) {
    Slack.TestHarness.Team team = slackState.getDefaultTeam();
    String channelId = request.getChannel();
    Slack.TestHarness.Channel channel = slackState.getChannel(team, channelId);
    for (String userId: request.getUsers()) {
        channel.addUser(slackState.getUser(team, userId));
    }
    Slack.ConversationsInviteResponse response = new Slack.ConversationsInviteResponse();
    response.setOk(true);
    return response;
}

```

## 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](https://api.slack.com/methods/conversations.list) for more information on the `conversations.list` request and response objects.

```java
public override Slack.ConversationsListResponse conversationsList(Slack.ConversationsListRequest request) {
        List<Slack.Conversation> conversations = new List<Slack.Conversation>();
       List<Slack.TestHarness.Channel> channels = slackState.getDefaultTeam().getChannels();
        for (Slack.TestHarness.Channel channel: channels) {
            Slack.Conversation conversation = new Slack.Conversation();
            conversation.setId(channel.getId());
            conversation.setName(channel.getName());
            conversations.add(conversation);
        }
        Slack.ConversationsListResponse response = new Slack.ConversationsListResponse();
        response.setOk(true);
        response.setChannels(conversations);
        return response;
    }

```

## 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](https://api.slack.com/methods/conversations.info) for more information on the `conversations.info` request and response objects.

```java
public override Slack.ConversationsInfoResponse conversationsInfo(Slack.ConversationsInfoRequest request) {
    Slack.ConversationsInfoResponse response = super.conversationsInfo(request);
    Slack.Conversation conversation = response.getChannel();
    Slack.Topic topic = new Slack.Topic();
    topic.setValue('Mock Topic Value');
    conversation.setTopic(topic);
    response.setChannel(conversation);
    return response;
}

```

## 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](https://api.slack.com/methods/pins.add) for more information on the pins.add request and response objects.

```java
Map<String, List<String>> pins = new Map<String, List<String>>();

public override Slack.PinsAddResponse pinsAdd(Slack.PinsAddRequest request) {
    String channelId = request.getChannel();
    String timestamp = request.getTimestamp();
    if (!pins.containsKey(channelId)) {
        pins.put(channelId, new List<String>());
    }
    if (!pins.get(channelId).contains(timestamp)) {
        pins.get(channelId).add(timestamp);
    }
    Slack.PinsAddResponse response = new Slack.PinsAddResponse();
    response.setOk(true);
    return response;
}
```

## 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](https://api.slack.com/methods/pins.list) for more information on the `pins.list` request and response objects.

```java
Map<String, List<String>> pins = new Map<String, List<String>>();

public override Slack.PinsListResponse pinsList(Slack.PinsListRequest request) {
    String channelId = request.getChannel();
    Slack.TestHarness.Channel channel = slackState.getChannel(slackState.getDefaultTeam(), channelId);
    if (!pins.containsKey(channelId)) {
        pins.put(channelId, new List<String>());
    }
    List<Slack.PinsListResponse.MessageItem> items = new List<Slack.PinsListResponse.MessageItem>();
    for (String pinTs: pins.get(channelId)) {
        Slack.PinsListResponse.MessageItem item = new Slack.PinsListResponse.MessageItem();
        item.setChannel(channelId);
        item.setType('message');
        items.add(item);
    }
    Slack.PinsListResponse response = new Slack.PinsListResponse();
    response.setOk(true);
    response.setItems(items);
    return response;
}
```

## 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](https://api.slack.com/methods/pins.remove) for more information on the `pins.remove` request and response objects.

```java
Map<String, List<String>> pins = new Map<String, List<String>>();

public override Slack.PinsRemoveResponse pinsRemove(Slack.PinsRemoveRequest request) {
    String channelId = request.getChannel();
    String timestamp = request.getTimestamp();
    if (pins.containsKey(channelId) && pins.get(channelId).contains(timestamp)) {
        pins.get(channelId).remove(pins.get(channelId).indexOf(timestamp));
    }
    Slack.PinsRemoveResponse response = new Slack.PinsRemoveResponse();
    response.setOk(true);
    return response;
}

```
