2022-12-27 07:27:36 +02:00
package components
import (
"fmt"
2022-12-27 13:52:20 +02:00
"strings"
2022-12-27 07:27:36 +02:00
"github.com/jesseduffield/gocui"
2023-02-12 00:53:57 +02:00
"github.com/samber/lo"
2022-12-27 07:27:36 +02:00
)
2022-12-28 02:27:48 +02:00
type ViewDriver struct {
2022-12-27 07:27:36 +02:00
// context is prepended to any error messages e.g. 'context: "current view"'
2023-02-25 04:08:45 +02:00
context string
getView func ( ) * gocui . View
t * TestDriver
getSelectedLinesFn func ( ) ( [ ] string , error )
getSelectedRangeFn func ( ) ( int , int , error )
getSelectedLineIdxFn func ( ) ( int , error )
}
func ( self * ViewDriver ) getSelectedLines ( ) ( [ ] string , error ) {
if self . getSelectedLinesFn == nil {
view := self . t . gui . View ( self . getView ( ) . Name ( ) )
return [ ] string { view . SelectedLine ( ) } , nil
}
return self . getSelectedLinesFn ( )
}
func ( self * ViewDriver ) getSelectedRange ( ) ( int , int , error ) {
if self . getSelectedRangeFn == nil {
view := self . t . gui . View ( self . getView ( ) . Name ( ) )
idx := view . SelectedLineIdx ( )
return idx , idx , nil
}
return self . getSelectedRangeFn ( )
}
// even if you have a selected range, there may still be a line within that range
// which the cursor points at. This function returns that line index.
func ( self * ViewDriver ) getSelectedLineIdx ( ) ( int , error ) {
if self . getSelectedLineIdxFn == nil {
view := self . t . gui . View ( self . getView ( ) . Name ( ) )
return view . SelectedLineIdx ( ) , nil
}
return self . getSelectedLineIdxFn ( )
2022-12-27 07:27:36 +02:00
}
// asserts that the view has the expected title
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) Title ( expected * TextMatcher ) * ViewDriver {
2022-12-27 12:35:36 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2022-12-27 07:27:36 +02:00
actual := self . getView ( ) . Title
return expected . context ( fmt . Sprintf ( "%s title" , self . context ) ) . test ( actual )
} )
return self
}
2023-02-25 04:08:45 +02:00
// asserts that the view has lines matching the given matchers. One matcher must be passed for each line.
// If you only care about the top n lines, use the TopLines method instead.
2023-02-26 02:49:15 +02:00
// If you only care about a subset of lines, use the ContainsLines method instead.
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) Lines ( matchers ... * TextMatcher ) * ViewDriver {
2023-02-25 04:08:45 +02:00
self . validateMatchersPassed ( matchers )
2023-06-03 08:10:53 +02:00
self . LineCount ( EqualsInt ( len ( matchers ) ) )
2023-02-25 04:08:45 +02:00
return self . assertLines ( 0 , matchers ... )
}
2022-12-27 07:27:36 +02:00
// asserts that the view has lines matching the given matchers. So if three matchers
// are passed, we only check the first three lines of the view.
// This method is convenient when you have a list of commits but you only want to
// assert on the first couple of commits.
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) TopLines ( matchers ... * TextMatcher ) * ViewDriver {
2023-02-25 04:08:45 +02:00
self . validateMatchersPassed ( matchers )
self . validateEnoughLines ( matchers )
2022-12-27 07:27:36 +02:00
2023-02-25 04:08:45 +02:00
return self . assertLines ( 0 , matchers ... )
2022-12-27 07:27:36 +02:00
}
2023-07-19 14:02:43 +02:00
// Asserts on the visible lines of the view.
// Note, this assumes that the view's viewport is filled with lines
func ( self * ViewDriver ) VisibleLines ( matchers ... * TextMatcher ) * ViewDriver {
self . validateMatchersPassed ( matchers )
self . validateVisibleLineCount ( matchers )
// Get the origin of the view and offset that.
// Note that we don't do any retrying here so if we want to bring back retry logic
// we'll need to update this.
originY := self . getView ( ) . OriginY ( )
return self . assertLines ( originY , matchers ... )
}
2023-02-26 02:49:15 +02:00
// asserts that somewhere in the view there are consequetive lines matching the given matchers.
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) ContainsLines ( matchers ... * TextMatcher ) * ViewDriver {
2023-02-25 04:08:45 +02:00
self . validateMatchersPassed ( matchers )
self . validateEnoughLines ( matchers )
2022-12-27 07:27:36 +02:00
2023-02-25 04:08:45 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
content := self . getView ( ) . Buffer ( )
lines := strings . Split ( content , "\n" )
2022-12-27 07:27:36 +02:00
2023-02-25 04:08:45 +02:00
startIdx , endIdx , err := self . getSelectedRange ( )
2023-02-24 12:42:27 +02:00
2023-02-25 04:08:45 +02:00
for i := 0 ; i < len ( lines ) - len ( matchers ) + 1 ; i ++ {
matches := true
for j , matcher := range matchers {
checkIsSelected , matcher := matcher . checkIsSelected ( ) // strip the IsSelected matcher out
lineIdx := i + j
ok , _ := matcher . test ( lines [ lineIdx ] )
if ! ok {
matches = false
break
}
if checkIsSelected {
if err != nil {
matches = false
break
}
if lineIdx < startIdx || lineIdx > endIdx {
matches = false
break
}
}
}
if matches {
return true , ""
}
}
2023-02-24 12:42:27 +02:00
2023-02-25 04:08:45 +02:00
expectedContent := expectedContentFromMatchers ( matchers )
return false , fmt . Sprintf (
"Expected the following to be contained in the staging panel:\n-----\n%s\n-----\nBut got:\n-----\n%s\n-----\nSelected range: %d-%d" ,
expectedContent ,
content ,
startIdx ,
endIdx ,
)
} )
return self
2023-02-24 12:42:27 +02:00
}
2023-06-01 12:11:06 +02:00
func ( self * ViewDriver ) ContainsColoredText ( fgColorStr string , text string ) * ViewDriver {
self . t . assertWithRetries ( func ( ) ( bool , string ) {
view := self . getView ( )
ok := self . getView ( ) . ContainsColoredText ( fgColorStr , text )
if ! ok {
return false , fmt . Sprintf ( "expected view '%s' to contain colored text '%s' but it didn't" , view . Name ( ) , text )
}
return true , ""
} )
return self
}
func ( self * ViewDriver ) DoesNotContainColoredText ( fgColorStr string , text string ) * ViewDriver {
self . t . assertWithRetries ( func ( ) ( bool , string ) {
view := self . getView ( )
ok := ! self . getView ( ) . ContainsColoredText ( fgColorStr , text )
if ! ok {
return false , fmt . Sprintf ( "expected view '%s' to NOT contain colored text '%s' but it didn't" , view . Name ( ) , text )
}
return true , ""
} )
return self
}
2023-02-26 02:49:15 +02:00
// asserts on the lines that are selected in the view. Don't use the `IsSelected` matcher with this because it's redundant.
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) SelectedLines ( matchers ... * TextMatcher ) * ViewDriver {
2023-02-25 04:08:45 +02:00
self . validateMatchersPassed ( matchers )
self . validateEnoughLines ( matchers )
2023-02-24 12:42:27 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
selectedLines , err := self . getSelectedLines ( )
if err != nil {
return false , err . Error ( )
}
selectedContent := strings . Join ( selectedLines , "\n" )
expectedContent := expectedContentFromMatchers ( matchers )
if len ( selectedLines ) != len ( matchers ) {
return false , fmt . Sprintf ( "Expected the following to be selected:\n-----\n%s\n-----\nBut got:\n-----\n%s\n-----" , expectedContent , selectedContent )
}
for i , line := range selectedLines {
2023-02-25 04:08:45 +02:00
checkIsSelected , matcher := matchers [ i ] . checkIsSelected ( )
if checkIsSelected {
self . t . fail ( "You cannot use the IsSelected matcher with the SelectedLines method" )
}
ok , message := matcher . test ( line )
2023-02-24 12:42:27 +02:00
if ! ok {
return false , fmt . Sprintf ( "Error: %s. Expected the following to be selected:\n-----\n%s\n-----\nBut got:\n-----\n%s\n-----" , message , expectedContent , selectedContent )
}
}
return true , ""
} )
return self
}
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) validateMatchersPassed ( matchers [ ] * TextMatcher ) {
2023-02-25 04:08:45 +02:00
if len ( matchers ) < 1 {
self . t . fail ( "'Lines' methods require at least one matcher to be passed as an argument. If you are trying to assert that there are no lines, use .IsEmpty()" )
}
}
2023-02-24 12:42:27 +02:00
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) validateEnoughLines ( matchers [ ] * TextMatcher ) {
2023-03-19 06:46:17 +02:00
view := self . getView ( )
2023-02-25 04:08:45 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2023-03-19 06:46:17 +02:00
lines := view . BufferLines ( )
return len ( lines ) >= len ( matchers ) , fmt . Sprintf ( "unexpected number of lines in view '%s'. Expected at least %d, got %d" , view . Name ( ) , len ( matchers ) , len ( lines ) )
2023-02-24 12:42:27 +02:00
} )
}
2023-07-19 14:02:43 +02:00
// assumes the view's viewport is filled with lines
func ( self * ViewDriver ) validateVisibleLineCount ( matchers [ ] * TextMatcher ) {
view := self . getView ( )
self . t . assertWithRetries ( func ( ) ( bool , string ) {
count := view . InnerHeight ( ) + 1
return count == len ( matchers ) , fmt . Sprintf ( "unexpected number of visible lines in view '%s'. Expected exactly %d, got %d" , view . Name ( ) , len ( matchers ) , count )
} )
}
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) assertLines ( offset int , matchers ... * TextMatcher ) * ViewDriver {
2022-12-27 07:27:36 +02:00
view := self . getView ( )
2023-02-25 04:08:45 +02:00
for matcherIndex , matcher := range matchers {
lineIdx := matcherIndex + offset
2022-12-27 07:27:36 +02:00
checkIsSelected , matcher := matcher . checkIsSelected ( )
2022-12-27 12:35:36 +02:00
self . t . matchString ( matcher , fmt . Sprintf ( "Unexpected content in view '%s'." , view . Name ( ) ) ,
2022-12-27 07:27:36 +02:00
func ( ) string {
2023-02-25 04:08:45 +02:00
return view . BufferLines ( ) [ lineIdx ]
2022-12-27 07:27:36 +02:00
} ,
)
if checkIsSelected {
2022-12-27 12:35:36 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2023-02-25 04:08:45 +02:00
startIdx , endIdx , err := self . getSelectedRange ( )
if err != nil {
return false , err . Error ( )
}
if lineIdx < startIdx || lineIdx > endIdx {
if startIdx == endIdx {
return false , fmt . Sprintf ( "Unexpected selected line index in view '%s'. Expected %d, got %d" , view . Name ( ) , lineIdx , startIdx )
} else {
lines , err := self . getSelectedLines ( )
if err != nil {
return false , err . Error ( )
}
return false , fmt . Sprintf ( "Unexpected selected line index in view '%s'. Expected line %d to be in range %d to %d. Selected lines:\n---\n%s\n---\n\nExpected line: '%s'" , view . Name ( ) , lineIdx , startIdx , endIdx , strings . Join ( lines , "\n" ) , matcher . name ( ) )
}
}
return true , ""
2022-12-27 07:27:36 +02:00
} )
}
}
return self
}
// asserts on the content of the view i.e. the stuff within the view's frame.
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) Content ( matcher * TextMatcher ) * ViewDriver {
2022-12-27 12:35:36 +02:00
self . t . matchString ( matcher , fmt . Sprintf ( "%s: Unexpected content." , self . context ) ,
2022-12-27 07:27:36 +02:00
func ( ) string {
return self . getView ( ) . Buffer ( )
} ,
)
return self
}
2023-02-25 04:08:45 +02:00
// asserts on the selected line of the view. If your view has multiple lines selected,
// but also has a concept of a cursor position, this will assert on the line that
// the cursor is on. Otherwise it will assert on the first line of the selection.
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) SelectedLine ( matcher * TextMatcher ) * ViewDriver {
2023-02-24 12:42:27 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2023-02-25 04:08:45 +02:00
selectedLineIdx , err := self . getSelectedLineIdx ( )
2023-02-24 12:42:27 +02:00
if err != nil {
return false , err . Error ( )
}
2023-02-25 04:08:45 +02:00
viewLines := self . getView ( ) . BufferLines ( )
if selectedLineIdx >= len ( viewLines ) {
return false , fmt . Sprintf ( "%s: Expected view to have at least %d lines, but it only has %d" , self . context , selectedLineIdx + 1 , len ( viewLines ) )
2023-02-24 12:42:27 +02:00
}
2023-02-25 04:08:45 +02:00
value := viewLines [ selectedLineIdx ]
2023-02-24 12:42:27 +02:00
return matcher . context ( fmt . Sprintf ( "%s: Unexpected selected line." , self . context ) ) . test ( value )
} )
2022-12-27 07:27:36 +02:00
return self
}
// asserts on the index of the selected line. 0 is the first index, representing the line at the top of the view.
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) SelectedLineIdx ( expected int ) * ViewDriver {
2022-12-27 12:35:36 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2022-12-27 07:27:36 +02:00
actual := self . getView ( ) . SelectedLineIdx ( )
return expected == actual , fmt . Sprintf ( "%s: Expected selected line index to be %d, got %d" , self . context , expected , actual )
} )
return self
}
2023-02-12 00:53:57 +02:00
// focus the view (assumes the view is a side-view)
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) Focus ( ) * ViewDriver {
2022-12-27 07:27:36 +02:00
viewName := self . getView ( ) . Name ( )
2023-02-12 00:53:57 +02:00
type window struct {
name string
viewNames [ ] string
2022-12-27 07:27:36 +02:00
}
2023-02-12 00:53:57 +02:00
windows := [ ] window {
{ name : "status" , viewNames : [ ] string { "status" } } ,
2023-07-17 09:29:24 +02:00
{ name : "files" , viewNames : [ ] string { "files" , "worktrees" , "submodules" } } ,
2023-02-12 00:53:57 +02:00
{ name : "branches" , viewNames : [ ] string { "localBranches" , "remotes" , "tags" } } ,
{ name : "commits" , viewNames : [ ] string { "commits" , "reflogCommits" } } ,
{ name : "stash" , viewNames : [ ] string { "stash" } } ,
2022-12-27 07:27:36 +02:00
}
2023-02-12 00:53:57 +02:00
for windowIndex , window := range windows {
if lo . Contains ( window . viewNames , viewName ) {
tabIndex := lo . IndexOf ( window . viewNames , viewName )
// jump to the desired window
self . t . press ( self . t . keys . Universal . JumpToBlock [ windowIndex ] )
2022-12-27 07:27:36 +02:00
2023-02-12 00:53:57 +02:00
// assert we're in the window before continuing
self . t . assertWithRetries ( func ( ) ( bool , string ) {
currentWindowName := self . t . gui . CurrentContext ( ) . GetWindowName ( )
// by convention the window is named after the first view in the window
return currentWindowName == window . name , fmt . Sprintf ( "Expected to be in window '%s', but was in '%s'" , window . name , currentWindowName )
} )
// switch to the desired tab
currentViewName := self . t . gui . CurrentContext ( ) . GetViewName ( )
currentViewTabIndex := lo . IndexOf ( window . viewNames , currentViewName )
if tabIndex > currentViewTabIndex {
for i := 0 ; i < tabIndex - currentViewTabIndex ; i ++ {
self . t . press ( self . t . keys . Universal . NextTab )
}
} else if tabIndex < currentViewTabIndex {
for i := 0 ; i < currentViewTabIndex - tabIndex ; i ++ {
self . t . press ( self . t . keys . Universal . PrevTab )
}
}
// assert that we're now in the expected view
self . IsFocused ( )
return self
}
}
self . t . fail ( fmt . Sprintf ( "Cannot focus view %s: Focus() method not implemented" , viewName ) )
2022-12-27 07:27:36 +02:00
return self
}
// asserts that the view is focused
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) IsFocused ( ) * ViewDriver {
2022-12-27 12:35:36 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2022-12-27 07:27:36 +02:00
expected := self . getView ( ) . Name ( )
2022-12-27 12:35:36 +02:00
actual := self . t . gui . CurrentContext ( ) . GetView ( ) . Name ( )
2022-12-27 07:27:36 +02:00
return actual == expected , fmt . Sprintf ( "%s: Unexpected view focused. Expected %s, got %s" , self . context , expected , actual )
} )
return self
}
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) Press ( keyStr string ) * ViewDriver {
2022-12-27 07:27:36 +02:00
self . IsFocused ( )
2022-12-27 12:35:36 +02:00
self . t . press ( keyStr )
2022-12-27 07:27:36 +02:00
return self
}
// i.e. pressing down arrow
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) SelectNextItem ( ) * ViewDriver {
2022-12-27 12:35:36 +02:00
return self . Press ( self . t . keys . Universal . NextItem )
2022-12-27 07:27:36 +02:00
}
// i.e. pressing up arrow
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) SelectPreviousItem ( ) * ViewDriver {
2022-12-27 12:35:36 +02:00
return self . Press ( self . t . keys . Universal . PrevItem )
2022-12-27 07:27:36 +02:00
}
// i.e. pressing space
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) PressPrimaryAction ( ) * ViewDriver {
2022-12-27 12:35:36 +02:00
return self . Press ( self . t . keys . Universal . Select )
2022-12-27 07:27:36 +02:00
}
// i.e. pressing space
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) PressEnter ( ) * ViewDriver {
2022-12-27 12:35:36 +02:00
return self . Press ( self . t . keys . Universal . Confirm )
2022-12-27 07:27:36 +02:00
}
2023-01-21 13:38:14 +02:00
// i.e. pressing tab
func ( self * ViewDriver ) PressTab ( ) * ViewDriver {
return self . Press ( self . t . keys . Universal . TogglePanel )
}
2022-12-27 07:27:36 +02:00
// i.e. pressing escape
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) PressEscape ( ) * ViewDriver {
2022-12-27 12:35:36 +02:00
return self . Press ( self . t . keys . Universal . Return )
2022-12-27 07:27:36 +02:00
}
2023-02-25 04:08:45 +02:00
// this will look for a list item in the current panel and if it finds it, it will
// enter the keypresses required to navigate to it.
// The test will fail if:
// - the user is not in a list item
// - no list item is found containing the given text
// - multiple list items are found containing the given text in the initial page of items
//
// NOTE: this currently assumes that BufferLines returns all the lines that can be accessed.
// If this changes in future, we'll need to update this code to first attempt to find the item
// in the current page and failing that, jump to the top of the view and iterate through all of it,
// looking for the item.
2023-06-03 07:12:31 +02:00
func ( self * ViewDriver ) NavigateToLine ( matcher * TextMatcher ) * ViewDriver {
2022-12-27 07:27:36 +02:00
self . IsFocused ( )
2023-02-25 04:08:45 +02:00
view := self . getView ( )
var matchIndex int
self . t . assertWithRetries ( func ( ) ( bool , string ) {
matchIndex = - 1
var matches [ ] string
lines := view . BufferLines ( )
// first we look for a duplicate on the current screen. We won't bother looking beyond that though.
for i , line := range lines {
ok , _ := matcher . test ( line )
if ok {
matches = append ( matches , line )
matchIndex = i
}
}
if len ( matches ) > 1 {
return false , fmt . Sprintf ( "Found %d matches for `%s`, expected only a single match. Matching lines:\n%s" , len ( matches ) , matcher . name ( ) , strings . Join ( matches , "\n" ) )
} else if len ( matches ) == 0 {
return false , fmt . Sprintf ( "Could not find item matching: %s. Lines:\n%s" , matcher . name ( ) , strings . Join ( lines , "\n" ) )
} else {
return true , ""
}
} )
selectedLineIdx , err := self . getSelectedLineIdx ( )
if err != nil {
self . t . fail ( err . Error ( ) )
return self
}
if selectedLineIdx == matchIndex {
self . SelectedLine ( matcher )
} else if selectedLineIdx < matchIndex {
for i := selectedLineIdx ; i < matchIndex ; i ++ {
self . SelectNextItem ( )
}
self . SelectedLine ( matcher )
} else {
for i := selectedLineIdx ; i > matchIndex ; i -- {
self . SelectPreviousItem ( )
}
self . SelectedLine ( matcher )
}
2022-12-27 07:27:36 +02:00
return self
}
2022-12-27 12:25:11 +02:00
2022-12-27 13:52:20 +02:00
// returns true if the view is a list view and it contains no items
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) IsEmpty ( ) * ViewDriver {
2022-12-27 13:52:20 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
actual := strings . TrimSpace ( self . getView ( ) . Buffer ( ) )
return actual == "" , fmt . Sprintf ( "%s: Unexpected content in view: expected no content. Content: %s" , self . context , actual )
} )
return self
}
2023-06-03 08:10:53 +02:00
func ( self * ViewDriver ) LineCount ( matcher * IntMatcher ) * ViewDriver {
view := self . getView ( )
self . t . assertWithRetries ( func ( ) ( bool , string ) {
lineCount := self . getLineCount ( )
ok , _ := matcher . test ( lineCount )
return ok , fmt . Sprintf ( "unexpected number of lines in view '%s'. Expected %s, got %d" , view . Name ( ) , matcher . name ( ) , lineCount )
} )
return self
}
func ( self * ViewDriver ) getLineCount ( ) int {
// can't rely entirely on view.BufferLines because it returns 1 even if there's nothing in the view
if strings . TrimSpace ( self . getView ( ) . Buffer ( ) ) == "" {
return 0
2022-12-27 13:52:20 +02:00
}
2023-03-19 06:46:17 +02:00
view := self . getView ( )
2023-06-03 08:10:53 +02:00
return len ( view . BufferLines ( ) )
}
2023-03-19 06:46:17 +02:00
2023-06-03 08:10:53 +02:00
func ( self * ViewDriver ) IsVisible ( ) * ViewDriver {
2022-12-27 13:52:20 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2023-06-03 08:10:53 +02:00
return self . getView ( ) . Visible , fmt . Sprintf ( "%s: Expected view to be visible, but it was not" , self . context )
2022-12-27 13:52:20 +02:00
} )
2023-06-03 08:10:53 +02:00
return self
}
func ( self * ViewDriver ) IsInvisible ( ) * ViewDriver {
2022-12-27 13:52:20 +02:00
self . t . assertWithRetries ( func ( ) ( bool , string ) {
2023-06-03 08:10:53 +02:00
return ! self . getView ( ) . Visible , fmt . Sprintf ( "%s: Expected view to be visible, but it was not" , self . context )
} )
2022-12-27 13:52:20 +02:00
2023-06-03 08:10:53 +02:00
return self
}
2022-12-27 13:52:20 +02:00
2023-06-03 08:10:53 +02:00
// will filter or search depending on whether the view supports filtering/searching
func ( self * ViewDriver ) FilterOrSearch ( text string ) * ViewDriver {
self . IsFocused ( )
self . Press ( self . t . keys . Universal . StartSearch ) .
Tap ( func ( ) {
self . t . ExpectSearch ( ) .
2023-07-22 05:04:39 +02:00
Clear ( ) .
2023-06-03 08:10:53 +02:00
Type ( text ) .
Confirm ( )
self . t . Views ( ) . Search ( ) . IsVisible ( ) . Content ( Contains ( fmt . Sprintf ( "matches for '%s'" , text ) ) )
} )
2022-12-27 13:52:20 +02:00
return self
}
2022-12-27 12:25:11 +02:00
// for when you want to make some assertion unrelated to the current view
// without breaking the method chain
2022-12-28 02:27:48 +02:00
func ( self * ViewDriver ) Tap ( f func ( ) ) * ViewDriver {
2022-12-27 12:25:11 +02:00
f ( )
return self
}
2023-02-24 12:42:27 +02:00
2023-02-25 04:08:45 +02:00
// This purely exists as a convenience method for those who hate the trailing periods in multi-line method chains
func ( self * ViewDriver ) Self ( ) * ViewDriver {
return self
}
2023-06-03 07:12:31 +02:00
func expectedContentFromMatchers ( matchers [ ] * TextMatcher ) string {
return strings . Join ( lo . Map ( matchers , func ( matcher * TextMatcher , _ int ) string {
2023-02-24 12:42:27 +02:00
return matcher . name ( )
} ) , "\n" )
}