utils.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. import os
  2. from app import models, db, app
  3. from datetime import datetime
  4. import xlsxwriter, xlrd, json
  5. from flask_login import current_user
  6. #
  7. # Default VALUES
  8. #
  9. CLASSNAME_TESTCASESEQUENCE = 'GC.CLASSES_TESTCASESEQUENCE'
  10. CLASSNAME_TESTCASE = 'GC.CLASSES_TESTCASE'
  11. CLASSNAME_TESTSTEP = 'GC.CLASSES_TESTSTEPMASTER'
  12. BROWSER_TYPE = 'GC.BROWSER_FIREFOX'
  13. TESTCASE_TYPE = 'Browser'
  14. #
  15. # item categories
  16. #
  17. def getItemCategories():
  18. categories = {}
  19. categories['main'] = [
  20. 'testrun',
  21. 'testcase_sequence',
  22. 'testcase',
  23. 'teststep_sequence',
  24. 'teststep',
  25. ]
  26. return categories
  27. #
  28. # get name of the item_type
  29. #
  30. def getItemType(item_type, plural=False):
  31. # main items
  32. if item_type == 'testrun':
  33. name = 'Testrun'
  34. elif item_type == 'testcase_sequence':
  35. name = 'Test Case Sequence'
  36. elif item_type == 'testcase':
  37. name = 'Test Case'
  38. elif item_type == 'teststep_sequence':
  39. name = 'Test Step Sequence'
  40. elif item_type == 'teststep':
  41. name = 'Test Step'
  42. else:
  43. # wrong item_type
  44. return ''
  45. # check for plurals
  46. if plural:
  47. name += 's'
  48. return name
  49. #
  50. # generate choices of items
  51. #
  52. def getTestCaseSequences():
  53. choices = []
  54. for item in models.TestCaseSequence.query.all():
  55. choices.append((f'{item.id}', item.name))
  56. return choices
  57. def getDataFiles():
  58. choices = []
  59. for item in models.DataFile.query.all():
  60. choices.append((f'{item.id}', item.filename))
  61. return choices
  62. def getTestCases():
  63. choices = []
  64. for item in models.TestCase.query.all():
  65. choices.append((f'{item.id}', item.name))
  66. return choices
  67. def getTestStepSequences():
  68. choices = []
  69. for item in models.TestStepSequence.query.all():
  70. choices.append((f'{item.id}', item.name))
  71. return choices
  72. def getTestSteps():
  73. choices = []
  74. for item in models.TestStepExecution.query.all():
  75. choices.append((f'{item.id}', item.name))
  76. return choices
  77. def getClassNames():
  78. choices = []
  79. for item in models.ClassName.query.all():
  80. choices.append((f'{item.id}', item.name))
  81. return choices
  82. def getBrowserTypes():
  83. choices = []
  84. for item in models.BrowserType.query.all():
  85. choices.append((f'{item.id}', item.name))
  86. return choices
  87. def getTestCaseTypes():
  88. choices = []
  89. for item in models.TestCaseType.query.all():
  90. choices.append((f'{item.id}', item.name))
  91. return choices
  92. def getActivityTypes():
  93. choices = []
  94. for item in models.ActivityType.query.all():
  95. choices.append((f'{item.id}', item.name))
  96. return choices
  97. def getLocatorTypes():
  98. choices = []
  99. for item in models.LocatorType.query.all():
  100. choices.append((f'{item.id}', item.name))
  101. return choices
  102. #
  103. # Comaprisions
  104. #
  105. COMPARISIONS = [
  106. '=',
  107. '>',
  108. '<',
  109. '>=',
  110. '<=',
  111. '<>',
  112. ]
  113. def getComparisionChoices():
  114. return [('0', 'none')] + [(f'{i+1}', COMPARISIONS[i]) for i in range(len(COMPARISIONS))]
  115. def getComparisionId(option):
  116. for i in range(len(COMPARISIONS)):
  117. if option == COMPARISIONS[i]:
  118. return f'{i+1}'
  119. return '0'
  120. #
  121. # Get Items By Name
  122. #
  123. def getOrCreateClassNameByName(name, description):
  124. # get ClassName from DB
  125. classname = models.ClassName.query.filter_by(name=name).first()
  126. if classname is None:
  127. # create ClassName if it doesn't exist
  128. classname = models.ClassName(
  129. name=name,
  130. description=description,
  131. )
  132. db.session.add(classname)
  133. db.session.commit()
  134. app.logger.info(f'Created ClassName ID #{classname.id} by {current_user}.')
  135. return classname
  136. def getBrowserTypeByName(name):
  137. # browser mapper
  138. bm = {
  139. 'BROWSER_FIREFOX': "FF",
  140. 'BROWSER_CHROME': "Chrome",
  141. 'BROWSER_SAFARI': "Safari",
  142. 'BROWSER_EDGE': "Edge",
  143. }
  144. return models.BrowserType.query.filter_by(name=bm[name.split('.')[-1]]).first()
  145. def getTestCaseTypeByName(name):
  146. return models.TestCaseType.query.filter_by(name=name).first()
  147. def getActivityTypeByName(name):
  148. return models.ActivityType.query.filter_by(name=name).first()
  149. def getLocatorTypeByName(name):
  150. if name:
  151. return models.LocatorType.query.filter_by(name=name).first()
  152. else:
  153. return None
  154. def getBooleanValue(value):
  155. if value:
  156. return True
  157. else:
  158. return False
  159. #
  160. # Cascade Delete
  161. #
  162. def deleteCascade(item_type, item_id, ):
  163. #
  164. # implementation of cascade delete of items
  165. #
  166. # delete Testrun and its children
  167. if item_type == 'testrun':
  168. item = models.Testrun.query.get(item_id)
  169. # delete children TestCaseSequences
  170. for child in item.testcase_sequences:
  171. deleteCascade('testcase_sequence', child.id)
  172. # delete Testrun
  173. db.session.delete(item)
  174. db.session.commit()
  175. app.logger.info(f'Deleted {item_type} id {item_id} by {current_user}.')
  176. # delete TestCaseSequence and its children
  177. elif item_type == 'testcase_sequence':
  178. item = models.TestCaseSequence.query.get(item_id)
  179. # check if item has not more then one parent
  180. if len(item.testrun) <= 1:
  181. # delete children TestCases
  182. for child in item.testcases:
  183. deleteCascade('testcase', child.id)
  184. # delete TestCaseSequence
  185. db.session.delete(item)
  186. db.session.commit()
  187. app.logger.info(f'Deleted {item_type} id {item_id} by {current_user}.')
  188. # delete TestCase and its children
  189. elif item_type == 'testcase':
  190. item = models.TestCase.query.get(item_id)
  191. # check if item has not more then one parent
  192. if len(item.testcase_sequence) <= 1:
  193. # delete children TestCaseSequences
  194. for child in item.teststep_sequences:
  195. deleteCascade('teststep_sequence', child.id)
  196. # delete TestCase
  197. db.session.delete(item)
  198. db.session.commit()
  199. app.logger.info(f'Deleted {item_type} id {item_id} by {current_user}.')
  200. # delete TestCaseSequence and its children
  201. elif item_type == 'teststep_sequence':
  202. item = models.TestStepSequence.query.get(item_id)
  203. # check if item has not more then one parent
  204. if len(item.testcase) <= 1:
  205. # delete children TestStepExecutions
  206. for child in item.teststeps:
  207. deleteCascade('teststep', child.id)
  208. # delete TestCaseSequence
  209. db.session.delete(item)
  210. db.session.commit()
  211. app.logger.info(f'Deleted {item_type} id {item_id} by {current_user}.')
  212. # delete TestStepExecution
  213. elif item_type == 'teststep':
  214. item = models.TestStepExecution.query.get(item_id)
  215. db.session.delete(item)
  216. db.session.commit()
  217. app.logger.info(f'Deleted {item_type} id {item_id} by {current_user}.')
  218. # invalid type
  219. else:
  220. raise Exception(f'Item type {item_type} does not exists.')
  221. #
  222. # Testrun export/import
  223. #
  224. def exportXLSX(testrun_id):
  225. #
  226. # Exports Testrun to XLSX
  227. #
  228. # get testrun
  229. testrun = models.Testrun.query.get(testrun_id)
  230. testrun_json = testrun.to_json()
  231. # create workbook
  232. headers = {
  233. 'TestRun': [
  234. 'Attribute',
  235. 'Value',
  236. ],
  237. 'TestCaseSequence': [
  238. 'Number',
  239. 'SequenceClass',
  240. 'TestDataFileName',
  241. ],
  242. 'TestCase': [
  243. 'TestCaseSequenceNumber',
  244. 'TestCaseNumber',
  245. 'TestCaseClass'
  246. 'TestCaseType',
  247. 'Browser',
  248. ],
  249. 'TestStep': [
  250. 'TestCaseSequenceNumber',
  251. 'TestCaseNumber',
  252. 'TestStepNumber',
  253. 'TestStepClass',
  254. ],
  255. 'TestStepExecution': [
  256. 'TestCaseSequenceNumber',
  257. 'TestCaseNumber',
  258. 'TestStepNumber',
  259. 'TestStepExecutionNumber',
  260. 'Activity',
  261. 'LocatorType',
  262. 'Locator',
  263. 'Value',
  264. 'Comparison',
  265. 'Value2',
  266. 'Timeout',
  267. 'Optional',
  268. 'Release',
  269. ],
  270. }
  271. xlsx_file = f'Testrun_{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.xlsx'
  272. workbook = xlsxwriter.Workbook(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'static/files', xlsx_file))
  273. worksheets = {}
  274. for sheet in headers:
  275. worksheets[sheet] = workbook.add_worksheet(sheet)
  276. # write headers
  277. for key, items in headers.items():
  278. for col in range(len(items)):
  279. worksheets[key].write(0, col, items[col])
  280. # write data
  281. # to TestRun
  282. worksheets['TestRun'].write(1, 0, 'Export Format')
  283. worksheets['TestRun'].write(1, 1, 'XLSX')
  284. # to TestCaseSequence
  285. i = 1 # i for TestCaseSequence Number
  286. for testcase_sequence in testrun.testcase_sequences:
  287. worksheets['TestCaseSequence'].write(i, 0, i)
  288. worksheets['TestCaseSequence'].write(i, 1, testcase_sequence.classname.name)
  289. worksheets['TestCaseSequence'].write(i, 2, testcase_sequence.datafiles[0].filename)
  290. # to TestCase
  291. j = 1 # j for TestCase
  292. for testcase in testcase_sequence.testcases:
  293. worksheets['TestCase'].write(j, 0, i)
  294. worksheets['TestCase'].write(j, 1, j)
  295. worksheets['TestCase'].write(j, 2, testcase.classname.name)
  296. worksheets['TestCase'].write(j, 3, testcase.testcase_type.name)
  297. worksheets['TestCase'].write(j, 4, testcase.browser_type.name)
  298. # to TestStep
  299. k = 1 # k for TestStep
  300. for teststep_sequence in testcase.teststep_sequences:
  301. worksheets['TestStep'].write(k, 0, i)
  302. worksheets['TestStep'].write(k, 1, j)
  303. worksheets['TestStep'].write(k, 2, k)
  304. worksheets['TestStep'].write(k, 3, teststep_sequence.classname.name)
  305. # to TestStepExecution
  306. m = 1 # m for TestStepExecution
  307. for teststep in teststep_sequence.teststeps:
  308. worksheets['TestStepExecution'].write(m, 0, i)
  309. worksheets['TestStepExecution'].write(m, 1, j)
  310. worksheets['TestStepExecution'].write(m, 2, k)
  311. worksheets['TestStepExecution'].write(m, 3, m)
  312. worksheets['TestStepExecution'].write(m, 4, teststep.activity_type.name)
  313. worksheets['TestStepExecution'].write(m, 5, teststep.locator_type.name)
  314. worksheets['TestStepExecution'].write(m, 6, teststep.locator)
  315. worksheets['TestStepExecution'].write(m, 7, teststep.value)
  316. worksheets['TestStepExecution'].write(m, 8, teststep.comparision)
  317. worksheets['TestStepExecution'].write(m, 9, teststep.value2)
  318. worksheets['TestStepExecution'].write(m, 10, teststep.timeout)
  319. worksheets['TestStepExecution'].write(m, 11, teststep.optional)
  320. worksheets['TestStepExecution'].write(m, 12, teststep.release)
  321. m += 1
  322. k += 1
  323. j += 1
  324. i += 1
  325. workbook.close()
  326. return xlsx_file
  327. def importXLSX(xlsx_file, item_id=None):
  328. #
  329. # imports testrun from xlsx file
  330. #
  331. if item_id is None:
  332. app.logger.info(f'Importing a Testrun from {xlsx_file.filename} by {current_user}.')
  333. else:
  334. # get item
  335. testrun = models.Testrun.query.get(item_id)
  336. if testrun is None: # item does not exist
  337. raise Exception(f'Testrun ID #{item_id} does not exists.')
  338. app.logger.info(f'Updating Testrun ID #{item_id} from {xlsx_file.filename} by {current_user}.')
  339. # open xlsx
  340. try:
  341. xl = xlrd.open_workbook(file_contents=xlsx_file.read())
  342. except xlrd.XLRDError:
  343. raise Exception(f'File "{xlsx_file.filename}" could not be imporeted.')
  344. # get file name
  345. file_name = os.path.basename(xlsx_file.filename)
  346. # Testrun object
  347. if item_id is None:
  348. # create Testrun
  349. testrun = models.Testrun(
  350. name=file_name,
  351. description=f'Imported from "{file_name}".',
  352. creator=current_user,
  353. )
  354. db.session.add(testrun)
  355. db.session.commit()
  356. app.logger.info(f'Created Testrun ID #{testrun.id} by {current_user}.')
  357. else:
  358. # update Testrun
  359. testrun.description = f'Updated from "{file_name}".'
  360. testrun.editor = current_user
  361. testrun.edited = datetime.utcnow()
  362. db.session.commit()
  363. app.logger.info(f'Updated Testrun ID #{item_id} by {current_user}.')
  364. # TestCaseSequence objects
  365. if item_id is None:
  366. testcase_sequences = {}
  367. else:
  368. testcase_sequences = {i+1: testrun.testcase_sequences[i] for i in range(len(testrun.testcase_sequences))}
  369. if 'TestCaseSequence' in xl.sheet_names():
  370. # get sheet
  371. testcase_sequence_sheet = xl.sheet_by_name('TestCaseSequence')
  372. # get headers as dict
  373. headers = {h[1]: h[0] for h in enumerate(testcase_sequence_sheet.row_values(0))}
  374. # get TestCaseSequences
  375. for row in range(1, testcase_sequence_sheet.nrows):
  376. if headers.get('Number') is None:
  377. # default number is 1
  378. n = 1
  379. else:
  380. # get the number from sheet
  381. n = int(testcase_sequence_sheet.cell(row, headers['Number']).value)
  382. # ClassName
  383. if headers.get('SequenceClass') is None:
  384. # default ClassName name
  385. name = CLASSNAME_TESTCASESEQUENCE
  386. else:
  387. # get ClassName name from sheet
  388. name = testcase_sequence_sheet.cell(row, headers['SequenceClass']).value
  389. # get ClassName from DB or create if it doesn't exist
  390. classname = getOrCreateClassNameByName(name, f'Imported from "{file_name}".')
  391. # DataFile
  392. if headers.get('TestDataFileName') is None:
  393. # default DataFile name
  394. name = file_name
  395. else:
  396. # get DataFile name from sheet
  397. name = testcase_sequence_sheet.cell(row, headers['TestDataFileName']).value
  398. # get DataFile from DB
  399. datafile = models.DataFile.query.filter_by(filename=name).first()
  400. if datafile is None:
  401. # create DataFile if it doesn't exist
  402. datafile = models.DataFile(
  403. filename=name,
  404. creator=current_user,
  405. )
  406. db.session.add(datafile)
  407. db.session.commit()
  408. app.logger.info(f'Created DataFile ID #{datafile.id} by {current_user}.')
  409. # TestCaseSequence
  410. if n in testcase_sequences:
  411. # update item
  412. testcase_sequences[n].description = f'Updated from "{file_name}".'
  413. testcase_sequences[n].editor = current_user
  414. testcase_sequences[n].edited = datetime.utcnow()
  415. testcase_sequences[n].classname = classname
  416. testcase_sequences[n].datafiles = [datafile]
  417. db.session.commit()
  418. app.logger.info(f'Updated TestCaseSequence ID #{testcase_sequences[n].id} by {current_user}.')
  419. else:
  420. # create item
  421. testcase_sequences[n] = models.TestCaseSequence(
  422. name=f'{file_name}_{row}',
  423. description=f'Imported from "{file_name}"',
  424. creator=current_user,
  425. classname=classname,
  426. datafiles=[datafile],
  427. testrun=[testrun],
  428. )
  429. db.session.add(testcase_sequences[n])
  430. db.session.commit()
  431. app.logger.info(f'Created TestCaseSequence ID #{testcase_sequences[n].id} by {current_user}.')
  432. else:
  433. # create default TestCaseSequence
  434. # ClassName
  435. # get ClassName from DB or create if it doesn't exist
  436. classname = getOrCreateClassNameByName(CLASSNAME_TESTCASESEQUENCE, 'Default for TestCaseSequence.')
  437. # DataFile
  438. # get DataFile from DB
  439. datafile = models.DataFile.query.filter_by(filename=file_name).first()
  440. if datafile is None:
  441. # create DataFile if it doesn't exist
  442. datafile = models.DataFile(
  443. filename=file_name,
  444. creator=current_user,
  445. )
  446. db.session.add(datafile)
  447. db.session.commit()
  448. app.logger.info(f'Created DataFile ID #{datafile.id} by {current_user}.')
  449. # TestCaseSequence
  450. if 1 in testcase_sequences:
  451. # update item
  452. testcase_sequences[1].description = f'Updated to default.'
  453. testcase_sequences[1].editor = current_user
  454. testcase_sequences[1].edited = datetime.utcnow()
  455. testcase_sequences[1].classname = classname
  456. testcase_sequences[1].datafiles = [datafile]
  457. db.session.commit()
  458. app.logger.info(f'Updated TestCaseSequence ID #{testcase_sequences[1].id} by {current_user}.')
  459. else:
  460. # create item
  461. testcase_sequences[1] = models.TestCaseSequence(
  462. name=f'{file_name}',
  463. description=f'Default for "{file_name}"',
  464. creator=current_user,
  465. classname=classname,
  466. datafiles=[datafile],
  467. testrun=[testrun],
  468. )
  469. db.session.add(testcase_sequences[1])
  470. db.session.commit()
  471. app.logger.info(f'Created TestCaseSequence ID #{testcase_sequences[1].id} by {current_user}.')
  472. # TestCase objects
  473. if item_id is None:
  474. testcases = {i+1: {} for i in range(len(testcase_sequences))}
  475. else:
  476. testcases = {index: {j+1: item.testcases[j] for j in range(len(item.testcases))} for index, item in testcase_sequences.items()}
  477. if 'TestCase' in xl.sheet_names():
  478. # get sheet
  479. testcase_sheet = xl.sheet_by_name('TestCase')
  480. # get headers as dict
  481. headers = {h[1]: h[0] for h in enumerate(testcase_sheet.row_values(0))}
  482. # get TestCases
  483. for row in range(1, testcase_sheet.nrows):
  484. # get TestCaseSequenceNumber
  485. if headers.get('TestCaseSequenceNumber') is None:
  486. # default number is 1
  487. i = 1
  488. else:
  489. # get the number from sheet
  490. i = int(testcase_sheet.cell(row, headers['TestCaseSequenceNumber']).value)
  491. # get TestCaseNumber
  492. if headers.get('TestCaseNumber') is None:
  493. # default number is 1
  494. n = 1
  495. else:
  496. # get the number from sheet
  497. n = int(testcase_sheet.cell(row, headers['TestCaseNumber']).value)
  498. # ClassName
  499. if headers.get('TestCaseClass') is None:
  500. # default ClassName name
  501. name = CLASSNAME_TESTCASE
  502. else:
  503. # get ClassName name from sheet
  504. name = testcase_sheet.cell(row, headers['TestCaseClass']).value
  505. # get ClassName from DB or create if it doesn't exist
  506. classname = getOrCreateClassNameByName(name, f'Imported from "{file_name}".')
  507. # TestCase
  508. # Browser Type
  509. if headers.get('Browser') is None:
  510. raise Exception('Sheet "TestCase" does not contain "Browser" column.')
  511. else:
  512. name = testcase_sheet.cell(row, headers['Browser']).value
  513. browser_type = getBrowserTypeByName(name)
  514. if browser_type is None:
  515. raise Exception(f'Unknown browser type "{name}": sheet "TestCase", row {row+1}.')
  516. # TestCase Type
  517. if headers.get('TestCaseType') is None:
  518. raise Exception('Sheet "TestCase" does not contain "TestCaseType" column.')
  519. else:
  520. name = testcase_sheet.cell(row, headers['TestCaseType']).value
  521. testcase_type=getTestCaseTypeByName(name)
  522. if testcase_type is None:
  523. raise Exception(f'Unknown testcase type "{name}": sheet "TestCase" row {row+1}.')
  524. if n in testcases[i]:
  525. # update item
  526. testcases[i][n].description = f'Updated from "{file_name}".'
  527. testcases[i][n].editor = current_user
  528. testcases[i][n].edited = datetime.utcnow()
  529. testcases[i][n].classname = classname
  530. testcases[i][n].browser_type = browser_type
  531. testcases[i][n].testcase_type = testcase_type
  532. db.session.commit()
  533. app.logger.info(f'Updated TestCase ID #{testcases[n].id} by {current_user}.')
  534. else:
  535. # create item
  536. testcases[i][n] = models.TestCase(
  537. name=f'{file_name}_{row}',
  538. description=f'Imported from "{file_name}".',
  539. creator=current_user,
  540. classname=classname,
  541. browser_type=browser_type,
  542. testcase_type=testcase_type,
  543. testcase_sequence=[testcase_sequences[i]],
  544. )
  545. db.session.add(testcases[i][n])
  546. db.session.commit()
  547. app.logger.info(f'Created TestCase ID #{testcases[i][n].id} by {current_user}.')
  548. else:
  549. # create default TestCase
  550. # ClassName
  551. # get ClassName from DB or create if it doesn't exist
  552. classname = getOrCreateClassNameByName(CLASSNAME_TESTCASE, 'Default for TestCase.')
  553. # TestCase
  554. if 1 in testcases[1]:
  555. # update item
  556. testcases[1][1].description = f'Updated to default.'
  557. testcases[1][1].editor = current_user
  558. testcases[1][1].edited = datetime.utcnow()
  559. testcases[1][1].classname = classname
  560. testcases[1][1].browser_type = getBrowserTypeByName(BROWSER_TYPE)
  561. testcases[1][1].testcase_type = getTestCaseTypeByName(TESTCASE_TYPE)
  562. db.session.commit()
  563. app.logger.info(f'Updated TestCase ID #{testcases[1][1].id} by {current_user}.')
  564. else:
  565. # create item
  566. testcases[1][1] = models.TestCase(
  567. name=f'{file_name}',
  568. description=f'Default for "{file_name}".',
  569. creator=current_user,
  570. classname=classname,
  571. browser_type=getBrowserTypeByName(BROWSER_TYPE),
  572. testcase_type=getTestCaseTypeByName(TESTCASE_TYPE),
  573. testcase_sequence=[testcase_sequences[1]],
  574. )
  575. db.session.add(testcases[1][1])
  576. db.session.commit()
  577. app.logger.info(f'Created TestCase ID #{testcases[1][1].id} by {current_user}.')
  578. # create TestSteps
  579. teststeps = {}
  580. if 'TestStep' in xl.sheet_names():
  581. # get sheet
  582. teststep_sheet = xl.sheet_by_name('TestStep')
  583. # get headers as dict
  584. headers = {h[1]: h[0] for h in enumerate(teststep_sheet.row_values(0))}
  585. # get TestSteps
  586. for row in range(1, teststep_sheet.nrows):
  587. # get TestStepNumber
  588. if headers.get('TestStepNumber') is None:
  589. # default number is 1
  590. n = 1
  591. else:
  592. # get the number from sheet
  593. n = int(teststep_sheet.cell(row, headers['TestStepNumber']).value)
  594. # get TestCaseNumber
  595. if headers.get('TestCaseNumber') is None:
  596. # default number is 1
  597. j = 1
  598. else:
  599. # get the number from sheet
  600. j = int(teststep_sheet.cell(row, headers['TestCaseNumber']).value)
  601. # get TestCaseSequenceNumber
  602. if headers.get('TestCaseSequenceNumber') is None:
  603. # default number is 1
  604. i = 1
  605. else:
  606. # get the number from sheet
  607. i = int(teststep_sheet.cell(row, headers['TestCaseSequenceNumber']).value)
  608. # ClassName
  609. if headers.get('TestStepClass') is None:
  610. # default ClassName name
  611. name = CLASSNAME_TESTSTEP
  612. else:
  613. # get ClassName name from sheet
  614. name = teststep_sheet.cell(row, headers['TestStepClass']).value
  615. # get ClassName from DB or create if it doesn't exist
  616. classname = getOrCreateClassNameByName(name, f'Imported from "{file_name}".')
  617. # TestCase
  618. # ---------------------------------------------------------------> continue with update
  619. teststeps[n] = models.TestStepSequence(
  620. name=f'{file_name}_{row}',
  621. description=f'Imported from "{file_name}"',
  622. creator=current_user,
  623. classname=classname,
  624. testcase=[testcases[i][j]],
  625. )
  626. db.session.add(teststeps[n])
  627. db.session.commit()
  628. app.logger.info(f'Created TestStepSequence id {teststeps[n].id} by {current_user}.')
  629. else:
  630. # create default TestStep
  631. # ClassName
  632. # get ClassName from DB or create if it doesn't exist
  633. classname = getOrCreateClassNameByName(CLASSNAME_TESTSTEP, 'Default for TestStep')
  634. # TestStep
  635. teststeps[1] = models.TestStepSequence(
  636. name=f'{file_name}_1',
  637. description=f'Default for "{file_name}"',
  638. creator=current_user,
  639. classname=classname,
  640. testcase=[testcases[1][1]]
  641. )
  642. db.session.add(teststeps[1])
  643. db.session.commit()
  644. app.logger.info(f'Created TestStepSequence id {teststeps[1].id} by {current_user}.')
  645. # create TestStepsExecutions
  646. if 'TestStepExecution' in xl.sheet_names():
  647. # get sheet
  648. teststep_execution_sheet = xl.sheet_by_name('TestStepExecution')
  649. # get headers as dict
  650. headers = {h[1]: h[0] for h in enumerate(teststep_execution_sheet.row_values(0))}
  651. # get TestStepExecutions
  652. for row in range(1, teststep_execution_sheet.nrows):
  653. # get TestStepExecutionNumber
  654. if headers.get('TestStepExecutionNumber') is None:
  655. # default number is 1
  656. n = row
  657. else:
  658. # get the number from sheet
  659. n = int(teststep_execution_sheet.cell(row, headers['TestStepExecutionNumber']).value)
  660. # get TestStepNumber
  661. if headers.get('TestStepNumber') is None:
  662. # default number is 1
  663. teststep_n = 1
  664. else:
  665. # get the number from sheet
  666. teststep_n = int(teststep_execution_sheet.cell(row, headers['TestStepNumber']).value)
  667. # Activity Type
  668. if headers.get('Activity') is None:
  669. raise Exception('Sheet "TestStepExecution" does not contain "Activity" column.')
  670. else:
  671. name = teststep_execution_sheet.cell(row, headers['Activity']).value
  672. activity_type = getActivityTypeByName(name.upper())
  673. if activity_type is None:
  674. raise Exception(f'Unknown activity type "{name}": sheet "TestStepExecution", row {row+1}')
  675. # Locator Type
  676. if headers.get('LocatorType') is None:
  677. raise Exception('Sheet "TestStepExecution" does not contain "LocatorType" column.')
  678. else:
  679. locator_type = getLocatorTypeByName(teststep_execution_sheet.cell(row, headers['LocatorType']).value)
  680. # get Locator
  681. if headers.get('Locator') is None:
  682. locator = None
  683. else:
  684. locator = teststep_execution_sheet.cell(row, headers['Locator']).value or None
  685. # get Value
  686. if headers.get('Value') is None:
  687. value = None
  688. else:
  689. value = teststep_execution_sheet.cell(row, headers['Value']).value or None
  690. # get Value 2
  691. if headers.get('Value2') is None:
  692. value2 = None
  693. else:
  694. value2 = teststep_execution_sheet.cell(row, headers['Value2']).value or None
  695. # get Comparison
  696. if headers.get('Comparison') is None:
  697. comparision = None
  698. else:
  699. comparision = teststep_execution_sheet.cell(row, headers['Comparison']).value or None
  700. # get Timeout
  701. if headers.get('Timeout') is None:
  702. timeout = None
  703. else:
  704. timeout = teststep_execution_sheet.cell(row, headers['Timeout']).value or None
  705. # get Optional
  706. if headers.get('Optional') is None:
  707. optional = False
  708. else:
  709. optional = getBooleanValue(teststep_execution_sheet.cell(row, headers['Optional']).value)
  710. # get Release
  711. if headers.get('Release') is None:
  712. release = None
  713. else:
  714. release = teststep_execution_sheet.cell(row, headers['Release']).value or None
  715. # TestStepExecution
  716. teststepex = models.TestStepExecution(
  717. name=f'{file_name}_{row}',
  718. description=f'Imported from "{file_name}"',
  719. creator=current_user,
  720. teststep_sequence=teststeps[teststep_n],
  721. activity_type=activity_type,
  722. locator_type=locator_type,
  723. locator=locator,
  724. value=value,
  725. comparision=comparision,
  726. value2=value2,
  727. timeout=timeout,
  728. optional=optional,
  729. release=release,
  730. )
  731. db.session.add(teststepex)
  732. db.session.commit()
  733. app.logger.info(f'Created TestStepExecution id {teststepex.id} by {current_user}.')
  734. return 1