├── calc_step1 ├── runtest.bat └── calc.sikuli │ ├── btn2.png │ ├── btnC.png │ ├── btnExp.png │ ├── CalcApp.png │ ├── btnEqual.png │ ├── btnPlus.png │ ├── calc.py │ └── calc.html ├── calctest ├── images │ ├── btn2.png │ ├── btnC.png │ ├── CalcApp.png │ ├── btnEqual.png │ ├── btnExp.png │ ├── btnPlus.png │ └── start_menu.png ├── jybottest.bat ├── robottest.bat ├── CalcLib │ ├── common.py │ ├── sikuliwrapper.py │ ├── calc.py │ └── logger.py └── robot_suite │ └── verify_operations.txt ├── calc_step2 ├── calc.sikuli │ ├── btn2.png │ ├── btnC.png │ ├── btnExp.png │ ├── CalcApp.png │ ├── btnEqual.png │ ├── btnPlus.png │ ├── calc$py.class │ ├── calc.py │ └── calc.html ├── jybottest.bat ├── robottest.bat └── robot_suite │ └── verify_operations.txt └── README /calc_step1/runtest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | java -jar "C:\Program Files\Sikuli X\sikuli-script.jar" calc.sikuli -------------------------------------------------------------------------------- /calctest/images/btn2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calctest/images/btn2.png -------------------------------------------------------------------------------- /calctest/images/btnC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calctest/images/btnC.png -------------------------------------------------------------------------------- /calctest/images/CalcApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calctest/images/CalcApp.png -------------------------------------------------------------------------------- /calctest/images/btnEqual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calctest/images/btnEqual.png -------------------------------------------------------------------------------- /calctest/images/btnExp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calctest/images/btnExp.png -------------------------------------------------------------------------------- /calctest/images/btnPlus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calctest/images/btnPlus.png -------------------------------------------------------------------------------- /calctest/images/start_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calctest/images/start_menu.png -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/btn2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step1/calc.sikuli/btn2.png -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/btnC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step1/calc.sikuli/btnC.png -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/btnExp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step1/calc.sikuli/btnExp.png -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/btn2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step2/calc.sikuli/btn2.png -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/btnC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step2/calc.sikuli/btnC.png -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/btnExp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step2/calc.sikuli/btnExp.png -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/CalcApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step1/calc.sikuli/CalcApp.png -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/btnEqual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step1/calc.sikuli/btnEqual.png -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/btnPlus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step1/calc.sikuli/btnPlus.png -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/CalcApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step2/calc.sikuli/CalcApp.png -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/btnEqual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step2/calc.sikuli/btnEqual.png -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/btnPlus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step2/calc.sikuli/btnPlus.png -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/calc$py.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imikemo/Sikuli-and-Robot-Framework-Integration/HEAD/calc_step2/calc.sikuli/calc$py.class -------------------------------------------------------------------------------- /calctest/jybottest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set sikuli_jar=C:\Program Files\Sikuli X\sikuli-script.jar 4 | 5 | set CLASSPATH=%sikuli_jar% 6 | set JYTHONPATH=%sikuli_jar%/Lib 7 | 8 | jybot --pythonpath=CalcLib ^ 9 | --outputdir=results ^ 10 | --loglevel=TRACE ^ 11 | %* -------------------------------------------------------------------------------- /calc_step2/jybottest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set sikuli_jar=C:\Program Files\Sikuli X\sikuli-script.jar 4 | 5 | set CLASSPATH=%sikuli_jar% 6 | set JYTHONPATH=%sikuli_jar%/Lib 7 | 8 | jybot --pythonpath=calc.sikuli ^ 9 | --outputdir=results ^ 10 | --loglevel=TRACE ^ 11 | %* -------------------------------------------------------------------------------- /calctest/robottest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set sikuli_jar=C:\Program Files\Sikuli X\sikuli-script.jar 4 | 5 | java -cp "robotframework-2.5.5.jar;%sikuli_jar%" ^ 6 | -Dpython.path="%sikuli_jar%/Lib" ^ 7 | org.robotframework.RobotFramework ^ 8 | --pythonpath=CalcLib ^ 9 | --outputdir=results ^ 10 | --loglevel=TRACE ^ 11 | %* -------------------------------------------------------------------------------- /calc_step2/robottest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set sikuli_jar=C:\Program Files\Sikuli X\sikuli-script.jar 4 | 5 | java -cp "robotframework-2.5.5.jar;%sikuli_jar%" ^ 6 | -Dpython.path="%sikuli_jar%/Lib" ^ 7 | org.robotframework.RobotFramework ^ 8 | --pythonpath=calc.sikuli ^ 9 | --outputdir=results ^ 10 | --loglevel=TRACE ^ 11 | %* -------------------------------------------------------------------------------- /calc_step2/robot_suite/verify_operations.txt: -------------------------------------------------------------------------------- 1 | ***Settings*** 2 | Library calc.Calculator WITH NAME Calculator 3 | 4 | ***Test Cases*** 5 | Verify that 2 + 2 = 4 6 | Start App 7 | Verify App 8 | Perform Action 2 + 2 9 | Verify Result 4 10 | 11 | Verify that 2 + 2 = 5 12 | Start App 13 | Verify App 14 | Perform Action 2 + 2 15 | Verify Result 5 16 | -------------------------------------------------------------------------------- /calctest/CalcLib/common.py: -------------------------------------------------------------------------------- 1 | # Global variables, can be moved to config file 2 | cfgImageLibrary = "images" # image search directory 3 | cfgLoggingLevel = "debug" # logging level, possible values 'debug', 'info' 4 | 5 | # Custom Exception for verification failures 6 | class VerificationFailed(Exception): 7 | def __init__(self, value): 8 | self.value = value 9 | def __str__(self): 10 | return self.value -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ================================================ 2 | Sikuli and Robot Framework Integration Project 3 | ================================================ 4 | 5 | This is source files for my blogpost on blog.mykhailo.com. 6 | Each directory is a result of same name step described in the blogpost. 7 | 8 | To use "robottest.bat" files - robotframework.jar file is requited. 9 | It can be downloaded from Robot Framework official site. 10 | 11 | Best regards, 12 | Mykhailo Moroz 13 | -------------------------------------------------------------------------------- /calctest/robot_suite/verify_operations.txt: -------------------------------------------------------------------------------- 1 | ***Settings*** 2 | Library calc.Calculator WITH NAME Calculator 3 | 4 | ***Test Cases*** 5 | Verify that 2 + 2 = 4 6 | Start App 7 | Verify App 8 | Perform Action 2 + 2 9 | Verify Result 4 10 | 11 | Verify that 2 + 2 = 5 12 | Start App 13 | Verify App 14 | Perform Action 2 + 2 15 | Verify Result 5 16 | 17 | Click on non-existent button "Exp" 18 | Start App 19 | Verify App 20 | Perform Action 2 exp 2 21 | Verify Result 2 22 | -------------------------------------------------------------------------------- /calctest/CalcLib/sikuliwrapper.py: -------------------------------------------------------------------------------- 1 | import common 2 | from logger import * 3 | from sikuli.Sikuli import Region as SikuliRegion 4 | 5 | 6 | # enable slow motion if debug log level enabled 7 | if common.cfgLoggingLevel.lower() == 'debug': 8 | setShowActions(True) 9 | 10 | # =============================================== # 11 | # Overwritten sikuli methods # 12 | # =============================================== # 13 | 14 | # function for calling native sikuli methods 15 | def sikuli_method(name, *args, **kwargs): 16 | return sys.modules['sikuli.Sikuli'].__dict__[name](*args, **kwargs) 17 | 18 | # overwritten Screen.exists method 19 | def exists(target, timeout=0): 20 | addFoundImage(getFilename(target)) 21 | return sikuli_method('exists', target, float(timeout)) 22 | 23 | # =============================================== # 24 | # Overwritten sikuli classes # 25 | # =============================================== # 26 | 27 | # overwriten Sikuli Region class 28 | class Region(SikuliRegion, BaseLogger): 29 | 30 | def click(self, target, modifiers=0): 31 | try: 32 | return SikuliRegion.click(self, target, modifiers) 33 | except FindFailed, e: 34 | self.log.html_img("Find Filed", "images/" + getFilename(target)) 35 | self.log.screenshot(msg="Region", region=(self.getX(), self.getY(), self.getW(), self.getH())) 36 | raise e 37 | def exists(self, target, timeout=None): 38 | img = getFilename(target) 39 | reg = (self.getX(), self.getY(), self.getW(), self.getH()) 40 | addFoundImage(img, reg) 41 | return SikuliRegion.exists(self, target, timeout) -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/calc.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | from sikuli.Sikuli import * 3 | 4 | class Calculator(object): 5 | 6 | def __init__(self): 7 | self.appCoordinates = (0, 0, 1024, 768) 8 | 9 | def startApp(self): 10 | calcApp = App("Calculator") 11 | if not calcApp.window(): 12 | App.open("calc.exe"); wait(2) 13 | calcApp.focus(); wait(1) 14 | 15 | def verifyApp(self): 16 | # check application 17 | if exists("CalcApp.png"): 18 | print("PASS: Calculator window appeared") 19 | else: 20 | print("FAIL: No calculator window") 21 | 22 | def performAction(self, *args): 23 | # get application region 24 | find("CalcApp.png") 25 | 26 | match = getLastMatch() 27 | self.appCoordinates = (match.getX(), match.getY(), match.getW(), match.getH()) 28 | appRegion = Region(*self.appCoordinates) 29 | 30 | #rewrite action 31 | action = args[1] 32 | if args[1] == '+': 33 | action = 'Plus' 34 | elif args[1] == 'exp': 35 | action = 'Exp' 36 | 37 | with appRegion: 38 | click("btnC.png") 39 | 40 | click( "btn%s.png" % (args[0],) ) 41 | click( "btn%s.png" % (action,) ) 42 | click( "btn%s.png" % (args[2],) ) 43 | 44 | click("btnEqual.png") 45 | 46 | def verifyResult(self, *args): 47 | expected_result = str(eval(''.join(args))) 48 | actual_result = self.getResultFromClipboard() 49 | 50 | #verification 51 | if actual_result == expected_result: 52 | print("PASS: Action performed correctly and result equals %s" % expected_result) 53 | else: 54 | print("FAIL: Actual result '%s' is not equal to expected result '%s'" % (actual_result, expected_result)) 55 | 56 | def getResultFromClipboard(self): 57 | type('c', KEY_CTRL) 58 | return str(Env.getClipboard()) 59 | 60 | def runTest(self): 61 | self.startApp() 62 | self.verifyApp() 63 | 64 | actions = '2+2' 65 | self.performAction(*actions) 66 | self.verifyResult(*actions) 67 | 68 | if __name__ == "__main__": 69 | calc = Calculator() 70 | calc.runTest() 71 | -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/calc.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | from sikuli.Sikuli import * 3 | 4 | addImagePath("calc.sikuli") 5 | 6 | class Calculator(object): 7 | 8 | def __init__(self): 9 | self.appCoordinates = (0, 0, 1024, 768) 10 | 11 | def startApp(self): 12 | calcApp = App("Calculator") 13 | if not calcApp.window(): 14 | App.open("calc.exe"); wait(2) 15 | calcApp.focus(); wait(1) 16 | 17 | def verifyApp(self): 18 | # check application 19 | if exists("CalcApp.png"): 20 | print("PASS: Calculator window appeared") 21 | else: 22 | print("FAIL: No calculator window") 23 | 24 | def performAction(self, *args): 25 | # get application region 26 | find("CalcApp.png") 27 | 28 | match = getLastMatch() 29 | self.appCoordinates = (match.getX(), match.getY(), match.getW(), match.getH()) 30 | appRegion = Region(*self.appCoordinates) 31 | 32 | #rewrite action 33 | action = args[1] 34 | if args[1] == '+': 35 | action = 'Plus' 36 | elif args[1] == 'exp': 37 | action = 'Exp' 38 | 39 | with appRegion: 40 | click("btnC.png") 41 | 42 | click( "btn%s.png" % (args[0],) ) 43 | click( "btn%s.png" % (action,) ) 44 | click( "btn%s.png" % (args[2],) ) 45 | 46 | click("btnEqual.png") 47 | 48 | def verifyResult(self, *args, **kwargs): 49 | expected_result = str(eval(''.join(args))) 50 | actual_result = self.getResultFromClipboard() 51 | 52 | #verification 53 | print expected_result 54 | print actual_result 55 | if actual_result == expected_result: 56 | print("PASS: Action performed correctly and result equals %s" % expected_result) 57 | else: 58 | print("FAIL: Actual result '%s' is not equal to expected result '%s'" % (actual_result, expected_result)) 59 | 60 | def getResultFromClipboard(self): 61 | type('c', KEY_CTRL) 62 | return str(Env.getClipboard()) 63 | 64 | def runTest(self): 65 | self.startApp() 66 | self.verifyApp() 67 | 68 | actions = '2+2' 69 | self.performAction(*actions) 70 | self.verifyResult(*actions) 71 | 72 | if __name__ == "__main__": 73 | calc = Calculator() 74 | calc.runTest() 75 | -------------------------------------------------------------------------------- /calctest/CalcLib/calc.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | from sikuliwrapper import * 3 | 4 | #add custom image library 5 | addImagePath(common.cfgImageLibrary) 6 | 7 | class Calculator(BaseLogger): 8 | 9 | ROBOT_LIBRARY_SCOPE = 'TEST SUITE' 10 | 11 | def __init__(self): 12 | self.appCoordinates = (0, 0, 1024, 768) 13 | 14 | def startApp(self): 15 | calcApp = App("Calculator") 16 | if not calcApp.window(): 17 | App.open("calc.exe"); wait(2) 18 | calcApp.focus(); wait(1) 19 | 20 | def verifyApp(self): 21 | # check application 22 | if exists("CalcApp.png"): 23 | self.log.passed("Calculator window appeared") 24 | else: 25 | self.log.failed("No calculator window") 26 | 27 | def performAction(self, *args): 28 | # get application region 29 | find("CalcApp.png") 30 | 31 | match = getLastMatch() 32 | self.appCoordinates = (match.getX(), match.getY(), match.getW(), match.getH()) 33 | appRegion = Region(*self.appCoordinates) 34 | 35 | #rewrite action 36 | action = args[1] 37 | if args[1] == '+': 38 | action = 'Plus' 39 | elif args[1] == 'exp': 40 | action = 'Exp' 41 | 42 | appRegion.click("btnC.png") 43 | 44 | appRegion.click( "btn%s.png" % (args[0],) ) 45 | appRegion.click( "btn%s.png" % (action,) ) 46 | appRegion.click( "btn%s.png" % (args[2],) ) 47 | 48 | appRegion.click("btnEqual.png") 49 | 50 | def verifyResult(self, *args): 51 | expected_result = str(eval(''.join(args))) 52 | actual_result = self.getResultFromClipboard() 53 | 54 | #verification 55 | if actual_result == expected_result: 56 | self.log.passed("Action performed correctly and result equals %s" % expected_result) 57 | else: 58 | self.log.failed("Actual result '%s' is not equal to expected result '%s'" % (actual_result, expected_result)) 59 | 60 | def getResultFromClipboard(self): 61 | type('c', KEY_CTRL) 62 | return str(Env.getClipboard()) 63 | 64 | def getResultFromOCR(self): 65 | # text recognition 66 | textCoordinates = (self.appCoordinates[0] + 220, self.appCoordinates[1] + 45, 25, 15) 67 | textRegion = Region(*textCoordinates) 68 | return str(textRegion.text()) 69 | 70 | def runTest(self): 71 | self.startApp() 72 | self.verifyApp() 73 | 74 | actions = '2+2' 75 | self.performAction(*actions) 76 | self.verifyResult(*actions) 77 | 78 | #calc = Calculator() 79 | #calc.runTest() 80 | -------------------------------------------------------------------------------- /calctest/CalcLib/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import datetime 3 | import shutil 4 | import common 5 | from sikuli.Sikuli import * 6 | 7 | # hack to properly handle WARNING log level 8 | logging.addLevelName(logging.WARNING, 'WARN') 9 | # add HTML log level 10 | HTML = logging.INFO + 5 11 | logging.addLevelName(HTML, 'HTML') 12 | 13 | class RobotHandler(logging.Handler): 14 | def __init__(self): 15 | logging.Handler.__init__(self, level=logging.DEBUG) 16 | 17 | def emit(self, record): 18 | print self.format(record) 19 | 20 | def format(self, record): 21 | if not self.formatter: 22 | # add default formatter 23 | self.formatter = logging.Formatter('*%(levelname)s* %(message)s') 24 | return self.formatter.format(record) 25 | 26 | class RobotLogger(logging.Logger): 27 | def __init__(self, name='robot', level=logging.INFO): 28 | if common.cfgLoggingLevel.lower() == 'debug': 29 | level = logging.DEBUG 30 | logging.Logger.__init__(self, name, level) 31 | self.addHandler(RobotHandler()) 32 | 33 | def _get_unique_name(self, prefix="", suffix=""): 34 | now = datetime.datetime.now() 35 | return prefix + now.strftime('%Y-%m-%d_%H-%M-%S') + suffix 36 | 37 | def screenshot(self, msg="", folder="results/screenshots/", region=(0,0,1440,900)): 38 | name = self._get_unique_name(suffix=".png") 39 | img_src = capture(*region) 40 | shutil.copy(img_src, folder + name) 41 | self.html_img(msg, folder + name) 42 | 43 | def passed(self, msg, *args, **kwargs): 44 | self.info('PASS: ' + msg, *args, **kwargs) 45 | 46 | if self.isEnabledFor(logging.DEBUG) and len(getLastFoundImages()) != 0: 47 | # source image 48 | self.html_img("Source Image", common.cfgImageLibrary + '/' + getLastFoundImage()) 49 | # matched image 50 | last_match = SCREEN.getLastMatch() 51 | region = (last_match.getX(), last_match.getY(), last_match.getW(), last_match.getH()) 52 | self.screenshot(msg="Best Matches", folder='results/matches/', region=region) 53 | # score of match 54 | self.info("Matched with score: %s" % last_match.getScore()) 55 | 56 | def failed(self, msg, *args, **kwargs): 57 | if self.isEnabledFor(logging.DEBUG): 58 | if len(getLastFoundImages()) != 0: 59 | # source image 60 | self.html_img("Source Image", common.cfgImageLibrary + '/' + getLastFoundImage()) 61 | # screenshot 62 | self.screenshot() 63 | raise common.VerificationFailed(msg) 64 | 65 | def html(self, msg, *args, **kwargs): 66 | self.log(HTML, msg, *args, **kwargs) 67 | 68 | def html_img(self, msg, image): 69 | self.html('%s ' % (msg, image)) 70 | 71 | class BaseLogger(object): 72 | """ Base class for logging support """ 73 | log = RobotLogger() 74 | 75 | #============= Modification to RootLogger ===============# 76 | # Use class RobotLogger instead of RootLogger as it support 77 | # additional methods: passed(), failed() 78 | 79 | # setup log level for RootLogger 80 | #logging.basicConfig(level=logging.INFO) 81 | # remove default StreamHandler 82 | #logging.getLogger('').removeHandler(logging.getLogger('').handlers[0]) 83 | # add RobotHandler to the RootLogger 84 | #logging.getLogger('').addHandler(RobotHandler()) 85 | #========================================================# 86 | 87 | # =============================================== # 88 | # Helper functions methods # 89 | # =============================================== # 90 | 91 | # functions for accessing lastly searched images and region 92 | _lastFoundImages = [] 93 | _lastFoundRegion = None 94 | # flag for checking whether last image was already poped 95 | # to prevent appearence old images in log file 96 | _is_new_image = 0 97 | 98 | def getLastFoundImages(): 99 | return _lastFoundImages 100 | def getLastFoundImage(): 101 | _is_new_image = 0 102 | return _lastFoundImages.pop() 103 | def getLastFoundRegion(): 104 | reg = _lastFoundRegion 105 | _lastFoundRegion = None 106 | return reg 107 | def addFoundImage(img, reg=None): 108 | _lastFoundImages.append(img) 109 | _lastFoundRegion = reg 110 | _is_new_image = 1 111 | 112 | # return filename from pattern's target object 113 | def getFilename(target): 114 | try: 115 | filename = target.getFilename() 116 | except: 117 | filename = target 118 | return filename 119 | -------------------------------------------------------------------------------- /calc_step1/calc.sikuli/calc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 67 | 68 | 69 |
70 |

calc.sikuli\calc.sikuli

(Download this script) 71 |
72 |
 73 | from __future__ import with_statement
 74 | from sikuli.Sikuli import *
 75 | 
 76 | class Calculator(BaseLogger):
 77 | 
 78 |         def __init__(self):
 79 |                 self.appCoordinates = (0, 0, 1024, 768)
 80 | 
 81 |         def startApp(self):
 82 |                 calcApp = App("Calculator")
 83 |                 if not calcApp.window():
 84 |                                 App.open("calc.exe"); wait(2)
 85 |                 calcApp.focus(); wait(1)
 86 | 
 87 |         def verifyApp(self):
 88 |                 # check application
 89 |                 if exists():
 90 |                         print("PASS: Calculator window appeared")
 91 |                 else:
 92 |                         print("FAIL: No calculator window")
 93 | 
 94 |         def performAction(self, *args):
 95 |                 # get application region
 96 |                 find()
 97 | 
 98 |                 match = getLastMatch()
 99 |                 self.appCoordinates = (match.getX(), match.getY(), match.getW(), match.getH())
100 |                 appRegion = Region(*self.appCoordinates)
101 | 
102 |                 #rewrite action
103 |                 action = args[1]
104 |                 if args[1] == '+':
105 |                         action = 'Plus'
106 |                 elif args[1] == 'exp':
107 |                         action = 'Exp'
108 | 
109 |                 appRegion.click()
110 |                 with appRegion:
111 |                         click()
112 | 
113 |                         click(  % (args[0],) )
114 |                         click(  % (action,) )
115 |                         click(  % (args[2],) )
116 | 
117 |                         click()
118 | 
119 |         def verifyResult(self, *args):
120 |                 expected_result = str(eval(''.join(args)))
121 |                 actual_result = self.getResultFromClipboard()
122 | 
123 |                 #verification
124 |                 if actual_result == expected_result:
125 |                         print("PASS: Action performed correctly and result equals %s" % expected_result)
126 |                 else:
127 |                         print("FAIL: Actual result '%s' is not equal to expected result '%s'" % (actual_result, expected_result))
128 | 
129 |         def getResultFromClipboard(self):
130 |                 type('c', KEY_CTRL)
131 |                 return str(Env.getClipboard())
132 | 
133 |         def runTest(self):
134 |                 self.startApp()
135 |                 self.verifyApp()
136 | 
137 |                 actions = '2+2'
138 |                 self.performAction(*actions)
139 |                 self.verifyResult(*actions)
140 | 
141 | calc = Calculator()
142 | calc.runTest()
143 | 
144 | 145 | 146 | -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/calc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 67 | 68 | 69 |
70 |

calc.sikuli\calc.sikuli

(Download this script) 71 |
72 |
 73 | from __future__ import with_statement
 74 | from sikuli.Sikuli import *
 75 | 
 76 | class Calculator(BaseLogger):
 77 | 
 78 |         def __init__(self):
 79 |                 self.appCoordinates = (0, 0, 1024, 768)
 80 | 
 81 |         def startApp(self):
 82 |                 calcApp = App("Calculator")
 83 |                 if not calcApp.window():
 84 |                                 App.open("calc.exe"); wait(2)
 85 |                 calcApp.focus(); wait(1)
 86 | 
 87 |         def verifyApp(self):
 88 |                 # check application
 89 |                 if exists():
 90 |                         print("PASS: Calculator window appeared")
 91 |                 else:
 92 |                         print("FAIL: No calculator window")
 93 | 
 94 |         def performAction(self, *args):
 95 |                 # get application region
 96 |                 find()
 97 | 
 98 |                 match = getLastMatch()
 99 |                 self.appCoordinates = (match.getX(), match.getY(), match.getW(), match.getH())
100 |                 appRegion = Region(*self.appCoordinates)
101 | 
102 |                 #rewrite action
103 |                 action = args[1]
104 |                 if args[1] == '+':
105 |                         action = 'Plus'
106 |                 elif args[1] == 'exp':
107 |                         action = 'Exp'
108 | 
109 |                 appRegion.click()
110 |                 with appRegion:
111 |                         click()
112 | 
113 |                         click(  % (args[0],) )
114 |                         click(  % (action,) )
115 |                         click(  % (args[2],) )
116 | 
117 |                         click()
118 | 
119 |         def verifyResult(self, *args):
120 |                 expected_result = str(eval(''.join(args)))
121 |                 actual_result = self.getResultFromClipboard()
122 | 
123 |                 #verification
124 |                 if actual_result == expected_result:
125 |                         print("PASS: Action performed correctly and result equals %s" % expected_result)
126 |                 else:
127 |                         print("FAIL: Actual result '%s' is not equal to expected result '%s'" % (actual_result, expected_result))
128 | 
129 |         def getResultFromClipboard(self):
130 |                 type('c', KEY_CTRL)
131 |                 return str(Env.getClipboard())
132 | 
133 |         def runTest(self):
134 |                 self.startApp()
135 |                 self.verifyApp()
136 | 
137 |                 actions = '2+2'
138 |                 self.performAction(*actions)
139 |                 self.verifyResult(*actions)
140 | 
141 | calc = Calculator()
142 | calc.runTest()
143 | 
144 | 145 | 146 | --------------------------------------------------------------------------------