You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: slack_tester.go
    path of file: ./repos/botkube/test/commplatform
    
    the code of the file until where you have to start completion: package commplatform

import (
	"context"
	"errors"
	"fmt"
	"maps"
	"regexp"
	"strings"
	"testing"
	"time"

	"botkube.io/botube/test/diff"
	"github.com/araddon/dateparse"
	"github.com/google/uuid"
	"github.com/slack-go/slack"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"k8s.io/apimachinery/pkg/util/wait"

	"github.com/kubeshop/botkube/pkg/api"
	"github.com/kubeshop/botkube/pkg/bot"
	"github.com/kubeshop/botkube/pkg/bot/interactive"
	"github.com/kubeshop/botkube/pkg/formatx"
	"github.com/kubeshop/botkube/pkg/ptr"
)

var _ BotDriver = (*SlackTester)(nil)

const (
	slackInteractiveElementsMsgSuffix = ", with interactive elements"
)

var slackLinks = regexp.MustCompile(`<(?P<val>https://[^>]*)>`)

type SlackConfig struct {
	BotName                  string        `envconfig:"default=botkube"`
	CloudBotName             string        `envconfig:"default=botkubedev"`
	CloudBasedTestEnabled    bool          `envconfig:"default=true"`
	TesterName               string        `envconfig:"default=tester"`
	AdditionalContextMessage string        `envconfig:"optional"`
	TesterAppTo
    
func (s *SlackTester) WaitForMessagePostedWithAttachment(userID, channelID string, limitMessages int, assertFn ExpAttachmentInput) error {
	defer s.restoreMsgTsIfNeeded()
	renderer := bot.NewSlackRenderer()

	var expTime time.Time
	if !assertFn.Message.Timestamp.IsZero() {
		expTime = assertFn.Message.Timestamp
		assertFn.Message.Timestamp = time.Time{}
	}

	// we don't support the attachment anymore, so content is available as normal message
	return s.WaitForMessagePosted(userID, channelID, limitMessages, func(content string) (bool, int, string) {
		// for now, we use old slack, so we send messages as a markdown
		expMsg := normalizeAttachmentContent(renderer.MessageToMarkdown(interactive.CoreMessage{
			Message: assertFn.Message,
		}))
		if !expTime.IsZero() {
			body, timestamp := s.trimAttachmentTimestamp(content)
			content = normalizeAttachmentContent(body)
			gotEventTime, err := dateparse.ParseAny(timestamp)
			if err != nil {
				return false, 0, err.Error()
			}

			if err = diff.TimeWithinDuration(expTime, gotEventTime, time.Minute); err != nil {
				return false, 0, err.Error()
			}
		}

		expMsg = replaceEmojiWithTags(expMsg)
		if !strings.EqualFold(expMsg, content) {
			count := diff.CountMatchBlock(expMsg, content)
			msgDiff := diff.Diff(expMsg, content)
			return false, count, msgDiff
		}

		return true, 0, ""
	})
}