├── 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 |
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(144 | 145 | 146 | -------------------------------------------------------------------------------- /calc_step2/calc.sikuli/calc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 67 | 68 | 69 |): 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 |
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(144 | 145 | 146 | --------------------------------------------------------------------------------): 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 |