The Sikuli tutorials have sufficient information to get started, but it is useful to have a GUI to create tests with, so using http://www.pharocasts.com/2011/02/pharo-gui-with-polymorph.html, the Pharo class WidgetExamples new exampleBasicControls
can quickly make a GUI that works good enough (for Smalltalk, there is also an event recorder that does something similar to this). One major advantage of using Smalltalk for this is an older version of Smalltalk can be found that has a UI that matches the expectation (for example the window resize tutorial fails because Apple has updated the bottom right corner and scrollbars for safari).
Sikuli Tutorials:
| builder dialog checkBoxes | builder := ExampleBuilderMorph new. dialog := (builder newPluggableDialogWindow: 'Example groups') useDefaultOKButton. checkBoxes := Array new: 5. 1 to: 5 do: [ :index | checkBoxes at: index put: (dialog newCheckboxFor: (ValueHolder new contents: true) getSelected: #contents setSelected: #contents: label: 'The ', index asString,' Checkbox' help: 'This is a checkbox') ]. dialog contentMorph: ((dialog newRow: { dialog newGroupbox: 'A bunch of checkboxes' forAll: checkBoxes}) vResizing: #spaceFill); model: nil. builder openModal: dialog.
The Sikuli code is:
click(Example groups) # Necessary to ensure the window has focus for x in findAll([] The) click(x)
| builder dialog | builder := ExampleBuilderMorph new. dialog := (builder newPluggableDialogWindow: 'Example groups') useDefaultOKButton. dialog contentMorph: ((dialog newRow: { dialog newLabelGroup: { 'Wrong Checkbox Groupbox'-> (dialog newCheckboxFor: (ValueHolder new contents: false) getSelected: #contents setSelected: #contents: label: 'First Wrong Checkbox' help: 'This is a checkbox'). 'Groupbox'->(dialog newGroupbox: 'A groupbox' forAll: { dialog newButtonFor: nil action: nil label: 'First Wrong Button' help: 'This is a button'. dialog newButtonFor: nil action: nil label: 'Second Wrong Button' help: 'This is a button'}). 'The Right Group' -> (dialog newGroupbox: 'A bunch of checkboxes' forAll: { dialog newCheckboxFor: (ValueHolder new contents: false) getSelected: #contents setSelected: #contents: label: 'The First Checkbox' help: 'This is a checkbox'. dialog newCheckboxFor: (ValueHolder new contents: false) getSelected: #contents setSelected: #contents: label: 'The Second Checkbox is the right one' help: 'This is a checkbox'. dialog newCheckboxFor: (ValueHolder new contents: true) getSelected: #contents setSelected: #contents: label: 'The Third Checkbox is the wrong one' help: 'This is a checkbox'. })}}) vResizing: #spaceFill); model: nil. builder openModal: dialog.
Unfortunately this example wouldn't work based on the tutorial.
| dialog builder | builder := WidgetExamples new exampleBuilder. dialog := (builder newPluggableDialogWindow: 'Slider Controls') useDefaultOKButton. dialog contentMorph: ((dialog newRow: {dialog newLabelGroup: {('Slider' -> (dialog newSliderFor: (ValueHolder new contents: 0.5) getValue: #contents setValue: #contents: help: 'This is a slider'))} }) vResizing: #spaceFill); model: nil. builder openModal: dialog
Opening multiple dialogs and then running the example scripts generally updated only the dialog at the top of the screen.
Another dialog that has two sliders:
| dialog builder | builder := WidgetExamples new exampleBuilder. dialog := (builder newPluggableDialogWindow: 'Slider Controls') useDefaultOKButton. dialog contentMorph: ((dialog newRow: {dialog newLabelGroup: {('Slider 1' -> (dialog newSliderFor: (ValueHolder new contents: 0.6) getValue: #contents setValue: #contents: help: 'This is a slider')). ('Slider 2' -> (dialog newSliderFor: (ValueHolder new contents: 0.4) getValue: #contents setValue: #contents: help: 'This is a slider'))} }) vResizing: #spaceFill); model: nil. builder openModal: dialog
Env.addHotkey(Key.F1, KeyModifier.ALT+KeyModifier.CTRL, openAppleMenu)
Was successful by changing this to:
Env.addHotkey(Key.F5, KeyModifier.CTRL, openAppleMenu)
Suppose one wants to be more focused, however there are so many possible distractions. Having a measure of how many possible distractions one has open can help - similar to how displaying fuel efficiency changes driving behavior.
Furthermore, one may have certain windows open when working in a non-impacting test environment, and other windows open when touching production. This monitoring can minimize the number of mistakes and improve the use of read-only accounts.
The below code runs by searching for screenshots placed in the same directory as the script - these are png files (note that they need to be re-copied each time the script is updated). It runs as:
Bordens-iMac% ./SikuliX-IDE.app/Contents/runIDE -r ./scan_desktop_impact.sikuli running SikuliX-IDE: -Xmx512M -Dapple.laf.useScreenMenuBar -Dfile.encoding=UTF-8 -Dsikuli.FromCommandLine -jar ./SikuliX-IDE.app/Contents/sikuli-ide.jar -r ./scan_desktop_impact.sikuli [info] add hotkey: ⌃ F5 Press Control-F5 to quit _______________ **** _______________ ** _______________ *
Every 3 seconds the code prints two lines - a line of underscores for the number of screenshots in the directory, and a star for each of the screenshots that are matched. A video of this is:
The code is:
from sikuli import * import sys import os # Scan a directory for images and show the number of counts of matching on the screen. # Exit when Control-F5 is hit. Settings.UserLogs = True Settings.UserLogTime = True # Added hotkey to quit easily # http://doc.sikuli.org/globals.html#listening-to-global-hotkeys def quitFromKey(event): Debug.user("User selected to exit") exit(0) # exit # stop the current script, using exit(0) will close the IDE. # When the user pressed Ctrl+F5 exit this script Env.addHotkey(Key.F5, KeyModifier.CTRL, quitFromKey) print "Press Control-F5 to quit" # Revert this with: # Env.removeHotkey(Key.F5, KeyModifier.CTRL) # run for 8 hours, sleeping every 3 seconds. # run_time = 60 / 3 * 60 * 8 # run for 25 minutes - 1 pomodoro run_time = 25 * 60 / 3 while run_time > 0: count = 0 found_images = 0 for f in os.listdir(getBundlePath()): # Debug.user(f) if f.find(".png") != -1: count = count + 1 if exists(f): found_images = found_images + 1 # Debug.user("Found a prod image") if(count == 0): print "ERROR: Images not found - place files in ",getBundlePath() else: print " ","_" * count spaces = " " * (count - found_images) stars = "*" * found_images print spaces,stars sleep(3) run_time = run_time - 1 exit(0)