Skip to main content
Version: 26.3

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 on each iteration.

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 option in reverse order. To make the loop variable a reference to each of the items (so their values can be changed), use the by reference option. These options can be used at any point where options is indicated in the syntax.

Syntax:
repeat {options} [with | for] each subitemType [of | in] containingValue {options}
     statementList
end repeat

repeat {options} {with | for} variableOrList {options} [= | equals | equal to | as] each subitemType [of | in] containingValue {options}
     statementList
end repeat

repeat {options} [with | for] each {subitemType} variable {options} [of | in] containingValue {options}      statementList
end repeat

repeat {options} [with | for] {each} variableOrList {options} [of | in] containingValue {options}
     statementList
end repeat

repeat {options} [with {each} | for each] containingValue {options}
     statementList
end repeat

SubitemType is one of:
[character | char]
word {delimited by delimiter}
line {delimited by delimiter}
{text | list} item {delimited by delimiter}
[instance | occurrence] of valueOrPattern

Options is either or both of:
in [reverse | reversed] order
[as {a} | by] [container | reference {to}]

Example:

repeat with each item of myAccountList by reference -- use 'by reference' to make changes to items
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

Example:

-- Count the number of times each word occurs in a text file
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 -- step through all of the words in the file
add 1 to property (it) of wordCounts
end repeat

put "Word counts in file " & sourceFile & ":"
repeat with each [word, count] of wordCounts -- step through all of the keys and values
put word && "appears" && count && "times"
end repeat

Example:

repeat by reference with each line of file "/tmp/example"
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") into imageFiles // Stores a list of objects representing all of the files in the image collection named "OKButton"
delete each item of imageFiles which ends with ".imageinfo" // remove imageinfo files from the list
repeat with each image of ImageFiles // display a list of images and their size on disk
put image && ">>>" && the size of image
end repeat

Example:

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

Example:

// Iterate over a nested list using multiple loop variables:
set nestedList to [[a,b,c], [1,2,3,4,5], [d,e]]
repeat with each [alpha,beta,gamma...] in nestedList
put !"[[alpha]] :: [[beta]] :: [[gamma]]"
end repeat
--> a :: b :: c
--> 1 :: 2 :: [3,4,5]
--> d :: e ::
Tech Talk

These repeat with each formats execute the statements in statementList within the repeat loop (until the matching end repeat statement) exactly once for each subpart (as specified by subitemType) that is contained within the specified containingValue.

In all forms of the repeat with each statement, subitemType indicates the type of item being iterated over (in cases where subitemType is omitted, "item" is assumed), and containingValue is the specific object or container whose parts are being iterated over. The combinations of subitemType and containingValue available here are similar to those used with the Number Function for counting subparts of a value.

When used, variable is the name of the loop variable which will be assigned the value of a particular subitem each time through the repeat loop. In formats where no specific variable is specified, the variable it is used. If by reference is specified, variable (or it) is set to be a reference to each subitem rather than a copy of its value. This allows you to delete or make changes to the source value from within the loop. Otherwise, if by reference is not specified, then 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 the forms of repeat with each where variableOrList is indicated, you may specify either a single loop variable name or a list of variable names. When a list of variables is given, they are assigned from the list of values (if any) supplied by that iteration through the loop, as described in Storing Multiple Values At Once. For example, if the containingValue being iterated over is a nested list then the values from each sublist within it will be assigned to the list of variables. Similarly, some Custom Iterators may return a list of values on each call to their nextValue handler, which would then be assigned to the given list of variables.

As a special case, when the containingValue being iterated over is a property list, you may provide a list of two variable names which will be assigned the values of each key and its corresponding value for each property in the property list.

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.