Skip to main content

Repeat Loops

One of the great strengths of computers is their ability to perform repetitive tasks with ease. SenseTalk provides several different types of repeat loops for this purpose.

A repeat loop is used any time you want to execute one or more statements repeatedly some number of times. The statements to be repeated are preceded by one of the repeat statements described below, and must always be followed by an end repeat statement to mark the end of the loop. Repeat loops may be nested.

Repeat Forever

Behavior: This form of repeat loop repeats indefinitely until terminated. Usually, you do not really want your script to keep looping forever (a condition known by programmers as an “infinite loop”), so repeat forever loops typically include at least one exit, return, or pass statement that breaks out of the loop when some condition has been met: The word forever is optional.

Syntax:
repeat {forever}
    statementList
end repeat

Example:

repeat forever
get nextValue(partList)
if it is empty then exit repeat // Generally there will be some handling within a forever repeat loop that provides a way to exit the repeat loop
TypeText it
end repeat

Repeat Number Times or For Duration

Behavior: This form repeats the number of times specified by the expression number or for the amount of time specified by the duration.

Syntax:
repeat {for} number {times}
    statementList
end repeat

repeat {for} duration
    statementList
end repeat

Example:

repeat 6 times
click "Arrow"
end repeat

Example:

repeat 1 minute
If imagefound(imageName:"Notification", waitFor:0) then
Logwarning "The warning is still present."
wait 2
else
Log "The warning is gone."
Exit Repeat
end if
end repeat

Repeat Until Condition, Repeat Until Time

Behavior: This form of repeat loop executes until the condition expression evaluates to a value of true, or until a given date/time arrives. The condition or time expression is evaluated before the first and each subsequent execution of the loop.

Syntax:
repeat until condition
    statementList
end repeat

repeat until timeExpression
    statementList
end repeat

Example:

repeat until list is empty
put the last item of list
delete the last item of list
end repeat

Example:

on ScrollUntilFound ImageName, myTime
Repeat until imagefound(image:imageName,waitfor:mytime)
if the counter is greater than 10 // Read more about the counter below
throw "image not found", imageName&&"not found when scrolling."
end if
Typetext PageDown
Wait 1
end repeat
end ScrollUntilFound

Example:

repeat until "3:17 pm" // Repeats until the local system (eggPlant machine) clock hits 3:17 pm"
log "counting the seconds"
wait 1
end repeat

Repeat While

Behavior: This form of repeat loop will execute as long as the condition expression evaluates to a value of true. The condition is evaluated before the first and each subsequent execution of the loop.

Syntax:
repeat while condition
    statementList
end repeat

Example:

set CountDown to 1000
repeat while CountDown is greater than 500
put readtext("TimerTL","TimerLR") into CountDown // Uses OCR to read a dynamic value off the SUT's screen
wait 3
end repeat

Example:

put 10 into x
repeat while x < 100
add x to x
end repeat

Repeat With Variable = Start to Finish

Behavior: This form of repeat sets a variable to each of a sequence of values. The term up to or down to may be used instead of the word to to indicate whether the loop variable should be incremented (increased) or decremented (decreased) each time through the loop. If neither direction is specified, up to is assumed. A step option lets you specify an amount other than 1 by which the loop variable is changed.

Syntax:
repeat [with | for] variable [= | as | from] start {up | down} to finish {step stepAmount}
    statementList
end repeat

Example:

put "Countdown"
repeat with n=10 down to 1
put n
wait one second
end repeat
put "BOOM!"

Example:

repeat with n=1 to the number of lines in file "/tmp/legalDoc"
put n & ": " & line n of file "/tmp/legalDoc"
end repeat

Example:

repeat with rate = 4.75 to 8.5 step 0.25
put "Rate: " & rate & tab &"Payment: " & calcPayment(rate)
end repeat

Example:

repeat with discount = 50 down to 0 step 5
insert (amount - discount%) after discountList
end repeat

Tech Talk

The value of variable is set to the value of start before the first execution of the loop. Variable is then incremented (or decremented for “down to”) by the value of stepAmount (or by 1, if no stepAmount is given) before each subsequent repetition. The value of variable is compared to the value of finish before each execution. When variable is greater than finish (or less than finish for “down to”) the loop is terminated. If variable is a reference, it will be reset to an ordinary variable before use.

tip

When a repeat loop using a loop variable is nested inside another, be sure to use a different variable for each loop, in order to avoid conflicts.

Repeat With Each

The repeat with each form is perhaps the most powerful and useful of all of SenseTalk’s repeat loops. This form of repeat makes it easy to step through each of the values in a list, the words in a sentence, the lines of text in a file, or many other subdivisions of a value.

When using this form to repeat through the items of a list, etc., the repeat variable (or it) will be set to each of the values in turn, from the first to the last. To step through the values in the opposite order, include the phrase in reverse order.

Syntax:
repeat with each subitemType [of | in] containingItem {in [reverse | reversed] order } {[as {a} | by] reference}
    statementList
end repeat

repeat with variable = each subitemType [of | in] containingItem {in [reverse | reversed] order } {[as {a} | by] reference}
    statementList
end repeat

repeat with each {subitemType} variable [of | in] containingItem {in [reverse | reversed] order } {[as {a} | by] reference}
    statementList
end repeat

Example:

repeat with each item of myAccountList
set property balance of it to zero -- Set the balance of each account in a list of account objects to zero
end repeat

Example:

put empty into condensedList -- Start with nothing; gather all non-blank lines of a file into a container
put file "/tmp/somefile" into sourceText -- Read the file
repeat with each line of sourceText
if it is not empty then put it & return
after condensedList
end repeat -- Count the number of times each word occurs in a text file

Example:

answer file "Select a file to count its words" -- Get the file to be counted:
if the result is "Cancel" then exit handler
put it into sourceFile
put {:} into wordCounts -- Start with an empty property list
repeat with each word of file sourceFile
add 1 to property (it) of wordCounts
end repeat

Example:

put "Word counts in file " & sourceFile & ":"
repeat with each item of the keys of wordCounts
put it && "appears" && wordCounts.(it) && "times"
end repeat

Example:

repeat with each line of file "/tmp/example" by reference
if it begins with "#" then delete it -- Delete every line that begins with "#" in a text file:
end repeat

Example:

put files(SuiteInfo().imagesFolder&slash&"OKButton") as a list into imageFiles // Stores a list of objects representing all of the files in the image collection named "OKButton"
repeat with each item of ImageFiles
if it contains ".imageinfo" then delete it from ImageFiles // Checks whether the text representation of the file object contains the string ".imageinfo" and deletes the item from the list if so
end repeat

Example:

set the RemoteWorkInterval to .1
repeat with each item of everyimagelocation("CheckBox")
click it
end repeat
set the RemoteWorkInterval to .7

Tech Talk

These repeat formats execute the statements within the repeat loop (until the matching end repeat statement) exactly once for each object or part (as specified by subitemType) that is contained within the specified containingItem. Virtually any of the combinations of subitemType and containingItem that are allowed with the number function can be used (that is, anything that can be counted within some containing object or container).

In all forms of the repeat with each statement, subitemType indicates the type of item being iterated over (if omitted in the third format shown above, "item" is assumed), and containingItem is the specific object or container whose parts are being iterated over.

In the second and third formats, variable is the name of a variable which will be assigned the identifier or contents of a particular subitem each time through the repeat loop. In the first format, where no specific variable is specified, the variable it is used. If by reference is specified, variable is set to be a reference to each subitem. Otherwise, if variable (or it) is already a reference, it will be reset to be an ordinary variable before being used as the loop variable.

In cases where subitemType is a type of object, the long id of the specific subObject will be assigned to it or variable each time through the loop. In cases where subitemType is a type of text chunk, the actual chunk of text will be stored in it or in variable.

tip

When a repeat loop using a loop variable is nested inside another, be sure to use a different variable for each loop. In particular, watch out for nested repeats which implicitly use it as a loop variable.

Repeat At Least Once Until, Repeat At Least Once While

Behavior: Executes the statements within the repeat loop once before checking the condition, ensuring that the statements will be performed at least once.

Syntax:
repeat at least once until condition
    statementList
end repeat

repeat at least once while condition
    statementList
end repeat

Example:

repeat at least once until list is empty
put the last item of list
delete the last item of list
end repeat

Example:

// Use code like below to detect when you've scrolled to the bottom of a page/screen.
put RemoteScreenSize() into DUTScreenSize // Stores the size of the screen of the SUT
put (.25*DUTScreenSize.x, .25*DUTScreenSize.y, .75*DUTScreenSize.x, .75*DUTScreenSize.y) into ClippingRectangle
CaptureScreen (Name: "state", Rectangle: ClippingRectangle) // Captures a screenshot of the SUT, only in the center portion of the screen
put the result into refImage // Stores the file path of the CaptureScreen image in a variable
repeat at least once while not imageFound(image:refImage,searchRectangle:ClippingRectangle,waitFor:0) // Forces the statements within the repeat loop to happen at least once, even if the condition is immediately met
CaptureScreen (Name: "state", Rectangle: ClippingRectangle) // Captures a new screenshot of the SUT
put the result into refImage
TypeText PageDown // Scrolls the screen toward the bottom of the page
Wait 2.5 // Wait long enough to allow the scrolling action to "settle"
end repeat

Counter Function, RepeatIndex Function

Behavior: The counter or repeatIndex function returns the current iteration count of the innermost executing repeat loop. This approach is useful for keeping track of how many times a loop repeated or took action once a certain count is reached.

Syntax:
counter()
the counter
repeatIndex()
the repeatIndex

Example:

repeat for 3 minutes
if the counter is a multiple of 100 then put the counter
end repeat

Example:

repeat until imagefound(imagename:"NextButton",waitFor:0)
if repeatindex() = 2 then throw "Image not found", "Image not found while scrolling."
SwipeUp
wait 2
end repeat

Example:

function FindColorPercentage myImage,myColor // Declares the custom function FindColorPercentage with two parameters myImage and myColor
assert that myColor is not empty // Confirms that a value was passed in for the myColor parameter, and throws an exception if one was not
put the width of imageSize(myImage) into XDirection // Determines how many pixels wide the image is
put the height of imageSize(myImage) into YDirection
set TotalPixels to XDirection times YDirection // Calculates the total number of pixels in the captured image
set ColorPixels to 0
repeat YDirection times
put the counter - 1 into YCoord // Uses the counter to keep track of which coordinate we are operating on
repeat XDirection times
put the counter - 1 into XCoord
put imagecoloratlocation(myImage, (XCoord,YCoord)) into ReturnedColor // Uses the imageColoratLocation() function to retrieve the RGB value of the current pixel
if ReturnedColor is color(myColor) then add 1 to ColorPixels // Uses the color() function to compare the actual RGB value against the RGB value passed into the FindColorPercentage function
end repeat
end repeat
return round((ColorPixels/TotalPixels) * 100, 1) // Calculates the percentage of pixels matching that desired color
end function
tip

Use the counter in any type of repeat loop. Its value is set to one the first time through the loop and increases by one on each iteration. If used inside nested loops it reports the index of the innermost loop in which it resides.