func (cp *ConsoleProcess) Expect(value string, timeout ...time.Duration) (string, error) {
	opts := []expect.ExpectOpt{expect.String(value)}
	if len(timeout) > 0 {
		opts = append(opts, expect.WithTimeout(timeout[0]))
	}
	return cp.console.Expect(opts...)
}
Expect listens to the terminal output and returns once the expected value is found or
a timeout occurs
Default timeout is 10 seconds
package termtest
import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/user"
	"regexp"
	"runtime"
	"strings"
	"syscall"
	"testing"
	"time"
	expect "github.com/ActiveState/termtest/expect"
	"github.com/ActiveState/termtest/internal/osutils"
)
var (
	ErrNoProcess = errors.New("no command process seems to be running")
)
type errWaitTimeout struct {
	error
}
func (errWaitTimeout) Timeout() bool { return true }
var ErrWaitTimeout = errWaitTimeout{fmt.Errorf("timeout waiting for exit code")}
type ConsoleProcess struct {
	opts    Options
	errs    chan error
	console *expect.Console
	cmd     *exec.Cmd
	cmdName string
	ctx     context.Context
	cancel  func()
}
func NewTest(t *testing.T, opts Options) (*ConsoleProcess, error) {
	opts.ObserveExpect = TestExpectObserveFn(t)
	opts.ObserveSend = TestSendObserveFn(t)
	return New(opts)
}
func New(opts Options) (*ConsoleProcess, error) {
	if err := opts.Normalize(); err != nil {
		return nil, err
	}
	cmd := exec.Command(opts.CmdName, opts.Args...)
	cmd.Dir = opts.WorkDirectory
	cmd.Env = opts.Environment
	cmd.SysProcAttr = osutils.SysProcAttrForNewProcessGroup()
	cmdString := osutils.CmdString(cmd)
	if opts.HideCmdLine {
		cmdString = "*****"
	}
	fmt.Printf("Spawning '%s' from %s\n", cmdString, opts.WorkDirectory)
	conOpts := []expect.ConsoleOpt{
		expect.WithDefaultTimeout(opts.DefaultTimeout),
		expect.WithSendObserver(expect.SendObserver(opts.ObserveSend)),
		expect.WithExpectObserver(opts.ObserveExpect),
	}
	conOpts = append(conOpts, opts.ExtraOpts...)
	console, err := expect.NewConsole(conOpts...)
	if err != nil {
		return nil, err
	}
	if err = console.Pty.StartProcessInTerminal(cmd); err != nil {
		return nil, err
	}
	ctx, cancel := context.WithCancel(context.Background())
	cp := ConsoleProcess{
		opts:    opts,
		errs:    make(chan error),
		console: console,
		cmd:     cmd,
		cmdName: opts.CmdName,
		ctx:     ctx,
		cancel:  cancel,
	}
	go func() {
		defer close(cp.errs)
		err := cmd.Wait()
		select {
		case cp.errs <- err:
		case <-cp.ctx.Done():
			log.Println("ConsoleProcess cancelled!  You may have forgotten to call ExpectExitCode()")
			_ = console.Close()
			return
		}
		cp.console.Pty.WaitTillDrained()
		_ = console.Pty.CloseTTY()
	}()
	return &cp, nil
}
func (cp *ConsoleProcess) Close() error {
	cp.cancel()
	_ = cp.opts.CleanUp()
	if cp.cmd == nil || cp.cmd.Process == nil {
		return nil
	}
	if cp.cmd.ProcessState != nil && cp.cmd.ProcessState.Exited() {
		return nil
	}
	if err := cp.cmd.Process.Kill(); err == nil {
		return nil
	}
	return cp.cmd.Process.Signal(syscall.SIGTERM)
}
func (cp *ConsoleProcess) Executable() string {
	return cp.cmdName
}
func (cp *ConsoleProcess) WorkDirectory() string {
	return cp.opts.WorkDirectory
}
func (cp *ConsoleProcess) Snapshot() string {
	return cp.console.Pty.State.String()
}
func (cp *ConsoleProcess) TrimmedSnapshot() string {
	newlineRe := regexp.MustCompile(`\r?\n`)
	return newlineRe.ReplaceAllString(strings.TrimSpace(cp.Snapshot()), "")
}
func (cp *ConsoleProcess) ExpectRe(value string, timeout ...time.Duration) (string, error) {
	opts := []expect.ExpectOpt{expect.RegexpPattern(value)}
	if len(timeout) > 0 {
		opts = append(opts, expect.WithTimeout(timeout[0]))
	}
	return cp.console.Expect(opts...)
}
func (cp *ConsoleProcess) ExpectLongString(value string, timeout ...time.Duration) (string, error) {
	opts := []expect.ExpectOpt{expect.LongString(value)}
	if len(timeout) > 0 {
		opts = append(opts, expect.WithTimeout(timeout[0]))
	}
	return cp.console.Expect(opts...)
}