TestStepMaster.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. import baangt.base.GlobalConstants as GC
  2. from baangt.base.Timing.Timing import Timing
  3. from baangt.base.BrowserHandling.BrowserHandling import BrowserDriver
  4. from baangt.base.ApiHandling import ApiHandling
  5. import sys
  6. from pkg_resources import parse_version
  7. import logging
  8. from baangt.TestSteps.Exceptions import baangtTestStepException
  9. from baangt.TestSteps.AddressCreation import AddressCreate
  10. from baangt.base.PDFCompare import PDFCompare, PDFCompareDetails
  11. from baangt.base.Faker import Faker as baangtFaker
  12. from baangt.base.Utils import utils
  13. from baangt.base.RuntimeStatistics import Statistic
  14. import random
  15. import itertools
  16. logger = logging.getLogger("pyC")
  17. class TestStepMaster:
  18. def __init__(self, executeDirect=True, **kwargs):
  19. self.anchor = None
  20. self.anchorLocator = None
  21. self.anchorLocatorType = None
  22. self.testCaseStatus = None
  23. self.ifActive = False
  24. self.ifIsTrue = True
  25. self.elseIsTrue = False
  26. self.ifLis = [self.ifIsTrue]
  27. self.elseLis = [self.elseIsTrue]
  28. self.ifConditions = 0
  29. self.repeatIsTrue = [False]
  30. self.repeatDict = [] # used to store steps command of repeat data
  31. self.repeatData = [] # used to store RLP_ data to be looped in repeat
  32. self.repeatCount = [] # Used to store count of randomdata in loop
  33. self.repeatActive = 0 # to sync active repeat counts with repeat done and will be execute when both are equal
  34. self.repeatDone = 0
  35. self.baangtFaker = None
  36. self.statistics = Statistic()
  37. self.kwargs = kwargs
  38. self.testRunInstance = kwargs.get(GC.KWARGS_TESTRUNINSTANCE)
  39. self.testcaseDataDict = kwargs.get(GC.KWARGS_DATA)
  40. self.timing: Timing = kwargs.get(GC.KWARGS_TIMING)
  41. self.timingName = self.timing.takeTime(self.__class__.__name__, forceNew=True)
  42. self.browserSession: BrowserDriver = kwargs.get(GC.KWARGS_BROWSER)
  43. self.apiSession: ApiHandling = kwargs.get(GC.KWARGS_API_SESSION)
  44. self.testStepNumber = kwargs.get(GC.STRUCTURE_TESTSTEP) # Set in TestRunData by TestCaseMaster
  45. self.testRunUtil = self.testRunInstance.testRunUtils
  46. # Get the release from testrun-customizing if set: (will influence, whether or not elements will be executed)
  47. self.globalRelease = self.testRunInstance.globalSettings.get("Release", "")
  48. # check, if this TestStep has additional Parameters and if so, execute
  49. lSequence = self.testRunUtil.getSequenceByNumber(testRunName=self.testRunInstance.testRunName,
  50. sequence=kwargs.get(GC.STRUCTURE_TESTCASESEQUENCE))
  51. self.testCase = self.testRunUtil.getTestCaseByNumber(lSequence, kwargs.get(GC.STRUCTURE_TESTCASE))
  52. self.testStep = self.testRunUtil.getTestStepByNumber(self.testCase, self.testStepNumber)
  53. try:
  54. if self.testStep and len(self.testStep) > 1:
  55. if not isinstance(self.testStep[1], str) and executeDirect:
  56. # This TestStepMaster-Instance should actually do something - activitites are described
  57. # in the TestExecutionSteps.
  58. # Otherwise there's only a classname in TestStep[0]
  59. self.executeDirect(self.testStep[1][GC.STRUCTURE_TESTSTEPEXECUTION])
  60. # Teardown makes only sense, when we actually executed something directly in here
  61. # Otherwise (if it was 1 or 2 Tab-stops more to the left) we'd take execution time without
  62. # having done anything
  63. self.teardown()
  64. except Exception as e:
  65. logger.warning(f"Uncought exception {e}")
  66. utils.traceback(exception_in=e)
  67. self.statistics.update_teststep_sequence()
  68. def executeDirect(self, executionCommands):
  69. """
  70. Executes a sequence of Commands. Will be subclassed in other modules.
  71. :param executionCommands:
  72. :return:
  73. """
  74. for index, (key, command) in enumerate(executionCommands.items()):
  75. try:
  76. self.executeDirectSingle(index, command)
  77. except Exception as ex:
  78. # 2020-07-16: This Exception is cought, printed and then nothing. That's not good. The test run
  79. # continues forever, despite this exception. Correct way would be to set test case to error and stop
  80. # this test case
  81. # Before we change something here we should check, why the calling function raises an error.
  82. logger.critical(ex)
  83. self.testcaseDataDict[GC.TESTCASESTATUS] = GC.TESTCASESTATUS_ERROR
  84. return
  85. def manageNestedCondition(self, condition="", ifis=False):
  86. if condition.upper() == "IF":
  87. self.ifConditions += 1
  88. self.ifLis.append(ifis)
  89. self.elseLis.append(False)
  90. elif condition.upper() == "ELSE":
  91. self.elseLis[-1] = True
  92. elif condition.upper() == "ENDIF":
  93. self.ifConditions -= 1
  94. if self.ifConditions < 0:
  95. raise BaseException("Numbers of ENDIF are greater than IF.")
  96. self.ifLis.pop()
  97. self.elseLis.pop()
  98. assert len(self.ifLis) == self.ifConditions + 1 and len(self.elseLis) == self.ifConditions + 1
  99. self.ifIsTrue = self.ifLis[-1]
  100. self.elseIsTrue = self.elseLis[-1]
  101. def executeDirectSingle(self, commandNumber, command, replaceFromDict=None):
  102. """
  103. This will execute a single instruction
  104. """
  105. # when we have an IF-condition and it's condition was not TRUE, then skip whatever comes here until we
  106. # reach Endif
  107. if not self.ifIsTrue and not self.elseIsTrue:
  108. if command["Activity"].upper() == "IF":
  109. self.manageNestedCondition(condition=command["Activity"].upper(), ifis=self.ifIsTrue)
  110. return True
  111. if command["Activity"].upper() != "ELSE" and command["Activity"].upper() != "ENDIF":
  112. return True
  113. if self.repeatIsTrue[-1]: # If repeat statement is active then execute this
  114. if command["Activity"].upper() == "REPEAT": # To sync active repeat with repeat done
  115. self.repeatActive += 1
  116. if command["Activity"].upper() != "REPEAT-DONE": # store command in repeatDict
  117. self.repeatDict[-1][commandNumber] = command
  118. return
  119. else:
  120. self.repeatDone += 1 # to sync repeat done with active repeat
  121. if self.repeatDone < self.repeatActive: # if all repeat-done are not synced with repeat store the data
  122. self.repeatDict[-1][commandNumber] = command
  123. logger.info(command)
  124. return
  125. self.repeatIsTrue[-1] = False
  126. if self.repeatData[-1]:
  127. data_list = []
  128. if type(self.repeatData[-1]) is list:
  129. for data_dic in self.repeatData[-1]:
  130. keys, values = zip(*data_dic.items())
  131. final_values = []
  132. for value in values: # coverting none list values to list. Useful in make all possible data using itertools
  133. if type(value) is not list:
  134. final_values.append([value])
  135. else:
  136. final_values.append(value)
  137. data_l = [dict(zip(keys, v)) for v in itertools.product(*final_values)] # itertools to make all possible combinations
  138. data_list.extend(data_l)
  139. else:
  140. data_list = [self.repeatData[-1]]
  141. if len(self.repeatCount) > 0 and self.repeatCount[-1]: # get random data from list of data
  142. try:
  143. data_list = random.sample(data_list, int(self.repeatCount[-1]))
  144. except:
  145. pass
  146. if data_list:
  147. for data in data_list:
  148. temp_dic = dict(self.repeatDict[-1])
  149. processed_data = {}
  150. for key in temp_dic:
  151. try:
  152. processed_data = dict(temp_dic[key])
  153. except Exception as ex:
  154. logger.debug(ex)
  155. try:
  156. self.executeDirectSingle(key, processed_data, replaceFromDict=data)
  157. except Exception as ex:
  158. logger.info(ex)
  159. else:
  160. temp_dic = dict(self.repeatDict[-1])
  161. for key in temp_dic:
  162. try:
  163. processed_data = dict(temp_dic[key])
  164. except Exception as ex:
  165. logger.debug(ex)
  166. for ky in processed_data:
  167. try:
  168. processed_data[ky] = self.replaceVariables(processed_data[ky])
  169. except Exception as ex:
  170. logger.info(ex)
  171. try:
  172. self.executeDirectSingle(key, processed_data)
  173. except Exception as ex:
  174. logger.info(ex)
  175. del self.repeatIsTrue[-1]
  176. del self.repeatDict[-1]
  177. del self.repeatData[-1]
  178. del self.repeatCount[-1]
  179. self.repeatDone -= 1
  180. self.repeatActive -= 1
  181. return
  182. css, id, lActivity, lLocator, lLocatorType, xpath = self._extractAllSingleValues(command)
  183. if lActivity == "COMMENT":
  184. return # Comment's are ignored
  185. if self.anchor and xpath:
  186. if xpath[0:3] == '///': # Xpath doesn't want to use Anchor
  187. xpath = xpath[1:]
  188. logger.debug(f"Anchor active, but escaped. Using pure xpath: {xpath}")
  189. else:
  190. logger.debug(f"Anchor active. combining {self.anchorLocator} with {xpath}")
  191. xpath = self.anchorLocator + xpath
  192. lValue = str(command["Value"])
  193. lValue2 = str(command["Value2"])
  194. lComparison = command["Comparison"]
  195. lOptional = utils.anything2Boolean(command["Optional"])
  196. # check release line
  197. lRelease = command["Release"]
  198. # Timeout defaults to 20 seconds, if not set otherwise.
  199. lTimeout = TestStepMaster._setTimeout(command["Timeout"])
  200. lTimingString = f"TS {commandNumber} {lActivity.lower()}"
  201. self.timing.takeTime(lTimingString)
  202. logger.info(
  203. f"Executing TestStepDetail {commandNumber} with parameters: act={lActivity}, lType={lLocatorType}, loc={lLocator}, "
  204. f"Val1={lValue}, comp={lComparison}, Val2={lValue2}, Optional={lOptional}, timeout={lTimeout}")
  205. original_value = lValue # used as key to make rlp json dict and will be used further to make sheet name
  206. lValue, lValue2 = self.replaceAllVariables(lValue, lValue2, replaceFromDict=replaceFromDict)
  207. if not TestStepMaster.ifQualifyForExecution(self.globalRelease, lRelease):
  208. logger.debug(f"we skipped this line due to {lRelease} disqualifies according to {self.globalRelease} ")
  209. return
  210. if lActivity == "GOTOURL":
  211. self.browserSession.goToUrl(lValue)
  212. elif lActivity == "SETTEXT":
  213. self.browserSession.findByAndSetText(xpath=xpath, css=css, id=id, value=lValue, timeout=lTimeout,
  214. optional=lOptional)
  215. elif lActivity == "SETTEXTIF":
  216. self.browserSession.findByAndSetTextIf(xpath=xpath, css=css, id=id, value=lValue, timeout=lTimeout,
  217. optional=lOptional)
  218. elif lActivity == "FORCETEXT":
  219. self.browserSession.findByAndForceText(xpath=xpath, css=css, id=id, value=lValue, timeout=lTimeout,
  220. optional=lOptional)
  221. elif lActivity == "FORCETEXTIF":
  222. if lValue:
  223. self.browserSession.findByAndForceText(xpath=xpath, css=css, id=id, value=lValue, timeout=lTimeout,
  224. optional=lOptional)
  225. elif lActivity == "FORCETEXTJS":
  226. if lValue:
  227. self.browserSession.findByAndForceViaJS(xpath=xpath, css=css, id=id, value=lValue, timeout=lTimeout,
  228. optional=lOptional)
  229. elif lActivity == "SETANCHOR":
  230. if not lLocator:
  231. self.anchor = None
  232. self.anchorLocator = None
  233. self.anchorLocatorType = None
  234. else:
  235. found = self.browserSession.findBy(xpath=xpath, css=css, id=id, timeout=lTimeout)
  236. if found:
  237. self.anchor = self.browserSession.element
  238. self.anchorLocator = lLocator
  239. self.anchorLocatorType = lLocatorType
  240. logger.debug(f"Anchor set: {lLocatorType} {lLocator}")
  241. else:
  242. logger.error(f"Anchor should be set, but can't be found in the current page: {lLocatorType}, {lLocator}")
  243. raise ValueError(f"Anchor should be set, but can't be found in the current page: {lLocatorType}, {lLocator}")
  244. elif lActivity == 'HANDLEIFRAME':
  245. self.browserSession.handleIframe(lLocator)
  246. elif lActivity == 'SWITCHWINDOW':
  247. lWindow = lValue
  248. if lWindow.isnumeric():
  249. lWindow = int(lWindow)
  250. self.browserSession.handleWindow(windowNumber=lWindow, timeout=lTimeout)
  251. elif lActivity == "CLICK":
  252. self.browserSession.findByAndClick(xpath=xpath, css=css, id=id, timeout=lTimeout, optional=lOptional)
  253. elif lActivity == "CLICKIF":
  254. self.browserSession.findByAndClickIf(xpath=xpath, css=css, id=id, timeout=lTimeout, value=lValue,
  255. optional=lOptional)
  256. elif lActivity == "PAUSE":
  257. self.browserSession.sleep(seconds=float(lValue))
  258. elif lActivity == "IF":
  259. # Originally we had only Comparisons. Now we also want to check for existance of Field
  260. if not lValue and lLocatorType and lLocator:
  261. lValue = self.browserSession.findBy(xpath=xpath, css=css, id=id, optional=lOptional,
  262. timeout=lTimeout)
  263. self.__doComparisons(lComparison=lComparison, value1=lValue, value2=lValue2)
  264. logger.debug(f"IF-condition original Value: {original_value} (transformed: {lValue}) {lComparison} {lValue2} "
  265. f"evaluated to: {self.ifIsTrue} ")
  266. elif lActivity == "ELSE":
  267. if not self.ifIsTrue:
  268. self.manageNestedCondition(condition=lActivity)
  269. logger.debug("Executing ELSE-condition")
  270. else:
  271. self.ifIsTrue = False
  272. elif lActivity == "ENDIF":
  273. self.manageNestedCondition(condition=lActivity)
  274. elif lActivity == "REPEAT":
  275. self.repeatActive += 1
  276. self.repeatIsTrue.append(True)
  277. self.repeatDict.append({})
  278. if original_value not in self.testRunInstance.json_dict:
  279. self.testRunInstance.json_dict[original_value] = []
  280. self.testRunInstance.json_dict[original_value].append(lValue)
  281. self.repeatData.append(lValue)
  282. self.repeatCount.append(lValue2)
  283. elif lActivity == 'GOBACK':
  284. self.browserSession.goBack()
  285. elif lActivity == 'APIURL':
  286. self.apiSession.setBaseURL(lValue)
  287. elif lActivity == 'ENDPOINT':
  288. self.apiSession.setEndPoint(lValue)
  289. elif lActivity == 'POST':
  290. self.apiSession.postURL(content=lValue)
  291. elif lActivity == 'GET':
  292. self.apiSession.getURL()
  293. elif lActivity == 'HEADER':
  294. self.apiSession.setHeaders(setHeaderData=lValue)
  295. elif lActivity == 'SAVE':
  296. self.doSaveData(lValue, lValue2, lLocatorType, lLocator)
  297. elif lActivity == 'CLEAR':
  298. # Clear a variable:
  299. if self.testcaseDataDict.get(lValue):
  300. del self.testcaseDataDict[lValue]
  301. elif lActivity == 'SAVETO':
  302. # In this case, we need to parse the real field, not the representation of the replaced field value
  303. self.doSaveData(command['Value'], lValue2, lLocatorType, lLocator)
  304. elif lActivity == 'SUBMIT':
  305. self.browserSession.submit()
  306. elif lActivity == "ADDRESS_CREATE":
  307. # Create Address with option lValue and lValue2
  308. AddressCreate(lValue, lValue2)
  309. # Update testcaseDataDict with addressDict returned from
  310. AddressCreate.returnAddress()
  311. self.testcaseDataDict.update(AddressCreate.returnAddress())
  312. elif lActivity == 'ASSERT':
  313. value_found = self.browserSession.findByAndWaitForValue(xpath=xpath, css=css, id=id, optional=lOptional,
  314. timeout=lTimeout)
  315. if not self.__doComparisons(lComparison=lComparison, value1=value_found, value2=lValue):
  316. raise baangtTestStepException(f"Expected Value: {lValue}, Value found :{value_found} ")
  317. elif lActivity == 'IBAN':
  318. # Create Random IBAN. Value1 = Input-Parameter for IBAN-Function. Value2=Fieldname
  319. self.__getIBAN(lValue, lValue2)
  320. elif lActivity == 'PDFCOMPARE':
  321. self.doPDFComparison(lValue)
  322. elif lActivity == 'CHECKLINKS':
  323. self.checkLinks()
  324. elif lActivity == 'ALERTIF':
  325. self.browserSession.confirmAlertIfAny()
  326. elif lActivity == GC.TESTCASESTATUS_STOP.upper():
  327. self.testcaseDataDict[GC.TESTCASESTATUS_STOP] = "X" # will stop the test case
  328. elif lActivity == GC.TESTCASESTATUS_STOPERROR.upper():
  329. self.testcaseDataDict[GC.TESTCASESTATUS_STOPERROR] = "X" # will stop the test case and set error
  330. elif lActivity[0:3] == "ZZ_":
  331. # custom command. Do nothing and return
  332. return
  333. else:
  334. raise BaseException(f"Unknown command in TestStep {lActivity}")
  335. self.timing.takeTime(lTimingString)
  336. def _extractAllSingleValues(self, command):
  337. lActivity = command["Activity"].upper()
  338. lLocatorType = command["LocatorType"].upper()
  339. try:
  340. lLocator = self.replaceVariables(command["Locator"])
  341. except Exception as ex:
  342. logger.info(ex)
  343. if lLocator and not lLocatorType: # If locatorType is empty, default it to XPATH
  344. lLocatorType = 'XPATH'
  345. xpath, css, id = self.__setLocator(lLocatorType, lLocator)
  346. return css, id, lActivity, lLocator, lLocatorType, xpath
  347. def doPDFComparison(self, lValue, lFieldnameForResults="DOC_Compare"):
  348. lFiles = self.browserSession.findNewFiles()
  349. if len(lFiles) > 1:
  350. # fixme: Do something! There were more than 1 files since last check. Damn
  351. logger.critical(f"There were {len(lFiles)} files new since last check. Can't handle that. ")
  352. raise Exception
  353. elif len(lFiles) == 1:
  354. # Wonderful. Let's do the PDF-Comparison
  355. lPDFDataClass = PDFCompareDetails()
  356. lPDFDataClass.fileName = lFiles[0][0]
  357. lPDFDataClass.referenceID = lValue
  358. lDict = {"": lPDFDataClass}
  359. lPDFCompare = PDFCompare()
  360. lDict = lPDFCompare.compare_multiple(lDict)
  361. self.testcaseDataDict[lFieldnameForResults + "_Status"] = lDict[""].Status
  362. self.testcaseDataDict[lFieldnameForResults + "_Results"] = lDict[""].StatusText
  363. def replaceAllVariables(self, lValue, lValue2, replaceFromDict=None):
  364. # Replace variables from data file
  365. try:
  366. if len(lValue) > 0:
  367. lValue = self.replaceVariables(lValue, replaceFromDict=replaceFromDict)
  368. if len(lValue2) > 0:
  369. lValue2 = self.replaceVariables(lValue2, replaceFromDict=replaceFromDict)
  370. except Exception as ex:
  371. logger.warning(f"During replacement of variables an error happened: {ex}")
  372. return lValue, lValue2
  373. def __getIBAN(self, lValue, lValue2):
  374. from baangt.base.IBAN import IBAN
  375. if not lValue2:
  376. logger.critical("IBAN-Method called without destination field name in column 'Value 2'")
  377. return
  378. lIBAN = IBAN()
  379. self.testcaseDataDict[lValue2] = lIBAN.getRandomIBAN()
  380. pass
  381. def checkLinks(self):
  382. """
  383. Will check all links on the current webpage
  384. Result will be written into "CheckedLinks" in TestDataDict
  385. If theres a returncode >= 400 in the list, we'll mark the testcase as failed
  386. """
  387. if self.testcaseDataDict.get("CheckedLinks"):
  388. self.testcaseDataDict["Result_CheckedLinks"] += self.browserSession.checkLinks()
  389. else:
  390. self.testcaseDataDict["Result_CheckedLinks"] = self.browserSession.checkLinks()
  391. for entry in self.testcaseDataDict["Result_CheckedLinks"]:
  392. if entry[0] > 400:
  393. self.testcaseDataDict[GC.TESTCASESTATUS] = GC.TESTCASESTATUS_ERROR
  394. self.testcaseDataDict[GC.TESTCASEERRORLOG] = self.testcaseDataDict.get(GC.TESTCASEERRORLOG, "") \
  395. + "URL-Checker error"
  396. break
  397. @staticmethod
  398. def ifQualifyForExecution(version_global, version_line):
  399. """ This function will test version_global and version_line
  400. @return True or False
  401. """
  402. if not version_global.strip():
  403. # No value is defined in Release, return True
  404. return True
  405. if not version_line.strip():
  406. # we skipped this line
  407. return True
  408. # split the version line
  409. if not len(version_line.strip().split(" ")) == 2:
  410. logger.debug(f"Invalid release format {version_line} ")
  411. return True
  412. comp_operator, version = version_line.strip().split(" ")
  413. if comp_operator == "<":
  414. return parse_version(version_global) < parse_version(version)
  415. elif comp_operator == ">":
  416. return parse_version(version_global) > parse_version(version)
  417. elif comp_operator == ">=":
  418. return parse_version(version_global) >= parse_version(version)
  419. elif comp_operator == "<=":
  420. return parse_version(version_global) <= parse_version(version)
  421. elif comp_operator == "=" or comp_operator == "==":
  422. return parse_version(version_global) == parse_version(version)
  423. else:
  424. logger.debug(f"Global version {version_global}, line version {version_line} ")
  425. return False
  426. def doSaveData(self, toField, valueForField, lLocatorType, lLocator):
  427. """
  428. Save fields. Either from an existing DICT (usually in API-Mode) or from a Webelement (in Browser-Mode)
  429. :param toField:
  430. :param valueForField:
  431. :param lLocatorType:
  432. :param lLocator:
  433. :return: no return parameter. The implicit return is a value in a field.
  434. """
  435. if self.testCase[1][GC.KWARGS_TESTCASETYPE] == GC.KWARGS_BROWSER:
  436. xpath, css, id = TestStepMaster.__setLocator(lLocatorType, lLocator)
  437. self.testcaseDataDict[toField] = self.browserSession.findByAndWaitForValue(xpath=xpath, css=css, id=id)
  438. logger.debug(f"Saved {self.testcaseDataDict[toField]} to {toField}")
  439. elif self.testCase[1][GC.KWARGS_TESTCASETYPE] == GC.KWARGS_API_SESSION:
  440. self.testcaseDataDict[toField] = valueForField
  441. else:
  442. sys.exit("Testcase Type not supported")
  443. @staticmethod
  444. def __setLocator(lLocatorType, lLocator):
  445. return utils.setLocatorFromLocatorType(lLocatorType, lLocator)
  446. @staticmethod
  447. def _setTimeout(lTimeout):
  448. return 20 if not lTimeout else float(lTimeout)
  449. def __doComparisons(self, lComparison, value1, value2):
  450. if isinstance(value1, bool) or isinstance(value2, bool):
  451. value1 = utils.anything2Boolean(value1)
  452. value2 = utils.anything2Boolean(value2)
  453. if value2 == 'None':
  454. value2 = None
  455. logger.debug(f"Evaluating IF-Condition: Value1 = {value1}, comparison={lComparison}, value2={value2}")
  456. if lComparison == "=":
  457. if value1 == value2:
  458. self.manageNestedCondition(condition="IF", ifis=True)
  459. else:
  460. self.manageNestedCondition(condition="IF", ifis=False)
  461. elif lComparison == "!=":
  462. if value1 != value2:
  463. self.manageNestedCondition(condition="IF", ifis=True)
  464. else:
  465. self.manageNestedCondition(condition="IF", ifis=False)
  466. elif lComparison == ">":
  467. if value1 > value2:
  468. self.manageNestedCondition(condition="IF", ifis=True)
  469. else:
  470. self.manageNestedCondition(condition="IF", ifis=False)
  471. elif lComparison == "<":
  472. if value1 < value2:
  473. self.manageNestedCondition(condition="IF", ifis=True)
  474. else:
  475. self.manageNestedCondition(condition="IF", ifis=False)
  476. elif lComparison == ">=":
  477. if value1 >= value2:
  478. self.manageNestedCondition(condition="IF", ifis=True)
  479. else:
  480. self.manageNestedCondition(condition="IF", ifis=False)
  481. elif lComparison == "<=":
  482. if value1 <= value2:
  483. self.manageNestedCondition(condition="IF", ifis=True)
  484. else:
  485. self.manageNestedCondition(condition="IF", ifis=False)
  486. elif not lComparison: # Check only, if Value1 has a value.
  487. val = True if value1 else False
  488. self.manageNestedCondition(condition="IF", ifis=val)
  489. else:
  490. raise BaseException(f"Comparison Operator not supported/unknown {lComparison}")
  491. return self.ifIsTrue
  492. def execute(self):
  493. """Method is overwritten in all children/subclasses"""
  494. pass
  495. def teardown(self):
  496. if self.testCaseStatus:
  497. if not self.testcaseDataDict[GC.TESTCASESTATUS]:
  498. self.testcaseDataDict[GC.TESTCASESTATUS] = self.testCaseStatus
  499. elif self.testCaseStatus == GC.TESTCASESTATUS_SUCCESS:
  500. # We'll not overwrite a potential Error Status of the testcase
  501. pass
  502. elif self.testCaseStatus == GC.TESTCASESTATUS_ERROR:
  503. self.testcaseDataDict = GC.TESTCASESTATUS_ERROR
  504. else:
  505. sys.exit("No idea, what happened here. Unknown condition appeared")
  506. self.timing.takeTime(self.timingName)
  507. def replaceVariables(self, expression, replaceFromDict=None):
  508. """
  509. The syntax for variables is currently $(<column_name_from_data_file>). Multiple variables can be assigned
  510. in one cell, for instance perfectly fine: "http://$(BASEURL)/$(ENDPOINT)"
  511. There's a special syntax for the faker module: $(FAKER.<fakermethod>).
  512. Also a special syntax for API-Handling: $(APIHandling.<DictElementName>).
  513. @param expression: the current cell, either as fixed value, e.g. "Franzi" or with a varible $(DATE)
  514. @return: the replaced value, e.g. if expression was $(DATE) and the value in column "DATE" of data-file was
  515. "01.01.2020" then return will be "01.01.2020"
  516. """
  517. if "$(" not in expression:
  518. return expression
  519. while "$(" in expression:
  520. if expression[0:2] == "$(":
  521. left_part = ""
  522. else:
  523. left_part = expression.split("$(")[0]
  524. center = expression[len(left_part) + 2:]
  525. center = center.split(")")[0]
  526. right_part = expression[len(left_part) + len(center) + 3:]
  527. centerValue = ""
  528. if replaceFromDict: # json is supplied with repeat tag, that json is used here to get main data
  529. dic = replaceFromDict
  530. for key in center.split('.')[-1:]:
  531. dic = self.iterate_json(dic, key)
  532. centerValue = dic
  533. if centerValue: # if we got value from the passed json then bypass this if else conditions
  534. pass
  535. elif "." not in center:
  536. # Replace the variable with the value from data structure
  537. centerValue = self.testcaseDataDict.get(center)
  538. else:
  539. # This is a reference to a DICT with ".": for instance APIHandling.AnswerContent("<bla>")
  540. dictVariable = center.split(".")[0]
  541. dictValue = center.split(".")[1]
  542. if dictVariable == 'ANSWER_CONTENT':
  543. centerValue = self.apiSession.session[1].answerJSON.get(dictValue, "Empty")
  544. elif dictVariable == 'FAKER':
  545. # This is to call Faker Module with the Method, that is given after the .
  546. centerValue = self._getFakerData(dictValue)
  547. elif self.testcaseDataDict.get(dictVariable):
  548. dic = self.testcaseDataDict.get(dictVariable)
  549. for key in center.split('.')[1:]:
  550. dic = self.iterate_json(dic, key)
  551. centerValue = dic
  552. else:
  553. raise BaseException(f"Missing code to replace value for: {center}")
  554. if not centerValue:
  555. if center in self.testcaseDataDict.keys():
  556. # The variable exists, but has no value.
  557. centerValue = ""
  558. else:
  559. raise BaseException(f"Variable not found: {center}, input parameter was: {expression}")
  560. if not isinstance(centerValue, list) and not isinstance(centerValue, dict):
  561. expression = "".join([left_part, str(centerValue), right_part])
  562. else:
  563. expression = centerValue
  564. return expression
  565. def iterate_json(self, data, key):
  566. # itereate through list of json and create list of data from dictionary inside those list
  567. if type(data) is list:
  568. lis = []
  569. for dt in data:
  570. dt = self.iterate_json(dt, key)
  571. lis.append(dt)
  572. return lis
  573. elif type(data) is dict:
  574. return data.get(key)
  575. def _getFakerData(self, fakerMethod):
  576. if not self.baangtFaker:
  577. self.baangtFaker = baangtFaker()
  578. logger.debug(f"Calling faker with method: {fakerMethod}")
  579. return self.baangtFaker.fakerProxy(fakerMethod=fakerMethod)