Browse Source

Merge branch 'master' into exec

# Conflicts:
#	exec.sh
#	ubuntu/baangt/baangt
#	ubuntu/build/baangt/Analysis-00.toc
#	ubuntu/build/baangt/COLLECT-00.toc
#	ubuntu/build/baangt/EXE-00.toc
#	ubuntu/build/baangt/PKG-00.pkg
#	ubuntu/build/baangt/PYZ-00.pyz
#	ubuntu/build/baangt/PYZ-00.toc
#	ubuntu/build/baangt/baangt
#	ubuntu/build/baangt/warn-baangt.txt
#	ubuntu/build/baangt/xref-baangt.html
bernhardbuhl 4 years ago
parent
commit
8f31d5ad25
100 changed files with 751 additions and 212 deletions
  1. 2 1
      .gitignore
  2. 18 1
      README.md
  3. BIN
      SimpleTheInternet.xlsx
  4. 0 19
      TechSpecs/30 Ready/MULTIPROCESSING_REFACTOR.md
  5. 7 7
      TechSpecs/30 Ready/randomValues.md
  6. 0 0
      TechSpecs/60 InProgress/CREATE_EXECUTABLE.md
  7. 32 0
      TechSpecs/60 InProgress/MULTIPROCESSING_REFACTOR.md
  8. 79 0
      TechSpecs/60 InProgress/NestedLoopsOfData.md
  9. 0 0
      TechSpecs/60 InProgress/PDFComparisonMicroService.md
  10. 71 0
      TechSpecs/60 InProgress/SaveResults2Database.md
  11. 1 1
      TechSpecs/30 Ready/UI_ShowStatusOfTestrun.md
  12. 2 0
      baangt.py
  13. 3 0
      baangt/TestCase/TestCaseMaster.py
  14. BIN
      baangt/TestCase/TestCaseMaster.pyo
  15. BIN
      baangt/TestCase/__init__.pyo
  16. 50 51
      baangt/TestCaseSequence/TestCaseSequenceMaster.py
  17. BIN
      baangt/TestCaseSequence/TestCaseSequenceMaster.pyo
  18. 5 10
      baangt/TestCaseSequence/TestCaseSequenceParallel.py
  19. BIN
      baangt/TestCaseSequence/TestCaseSequenceParallel.pyo
  20. BIN
      baangt/TestCaseSequence/__init__.pyo
  21. BIN
      baangt/TestSteps/AddressCreation.pyo
  22. BIN
      baangt/TestSteps/Exceptions.pyo
  23. 2 0
      baangt/TestSteps/TestStepMaster.py
  24. BIN
      baangt/TestSteps/TestStepMaster.pyo
  25. BIN
      baangt/TestSteps/__init__.pyo
  26. BIN
      baangt/__init__.pyo
  27. BIN
      baangt/base/ApiHandling.pyo
  28. 69 37
      baangt/base/BrowserHandling/BrowserHandling.py
  29. BIN
      baangt/base/BrowserHandling/BrowserHandling.pyo
  30. BIN
      baangt/base/BrowserHandling/__init__.pyo
  31. BIN
      baangt/base/BrowserHandling/hookImpls.pyo
  32. 10 4
      baangt/base/CliAndInteractive.py
  33. BIN
      baangt/base/CliAndInteractive.pyo
  34. BIN
      baangt/base/CustGlobalConstants.pyo
  35. BIN
      baangt/base/DataBaseORM.pyo
  36. BIN
      baangt/base/ExportResults/ExportResults.pyo
  37. BIN
      baangt/base/ExportResults/__init__.pyo
  38. BIN
      baangt/base/ExportResults/hookImpls.pyo
  39. 2 1
      baangt/base/GlobalConstants.py
  40. BIN
      baangt/base/GlobalConstants.pyo
  41. BIN
      baangt/base/HandleDatabase.pyo
  42. BIN
      baangt/base/TestRun/TestRun.pyo
  43. BIN
      baangt/base/TestRun/__init__.pyo
  44. BIN
      baangt/base/TestRun/hookImpls.pyo
  45. BIN
      baangt/base/TestRunExcelImporter.pyo
  46. BIN
      baangt/base/TestRunUtils.pyo
  47. BIN
      baangt/base/Timing/Timing.pyo
  48. BIN
      baangt/base/Timing/__init__.pyo
  49. BIN
      baangt/base/Timing/hookImpls.pyo
  50. BIN
      baangt/base/Utils.pyo
  51. BIN
      baangt/base/__init__.pyo
  52. BIN
      baangt/hookSpecs.pyo
  53. BIN
      baangt/ui/ImportKatalonRecorder.pyo
  54. BIN
      baangt/ui/__init__.pyo
  55. BIN
      baangt/ui/ui.pyo
  56. 0 5
      baangtExec.py
  57. 2 0
      baangtIA.py
  58. 11 6
      ubuntu/baangt.spec
  59. BIN
      browserDrivers/chromedriver.exe
  60. BIN
      browserDrivers/chromedriver_78
  61. BIN
      browserDrivers/geckodriver
  62. BIN
      browserDrivers/geckodriver.exe
  63. BIN
      browserDrivers/msedgedriver.exe
  64. 0 0
      browsermob-proxy/bin/browsermob-proxy
  65. 10 0
      docs/BrowserDrivers.rst
  66. 1 1
      docs/ParametersConfigFile.rst
  67. 8 5
      docs/PlannedFeatures.rst
  68. BIN
      docs/_build/doctrees/BrowserDrivers.doctree
  69. BIN
      docs/_build/doctrees/DataFile.doctree
  70. BIN
      docs/_build/doctrees/Developer.doctree
  71. BIN
      docs/_build/doctrees/OverviewUsage.doctree
  72. BIN
      docs/_build/doctrees/ParametersConfigFile.doctree
  73. BIN
      docs/_build/doctrees/PlannedFeatures.doctree
  74. BIN
      docs/_build/doctrees/SimpleAPI.doctree
  75. BIN
      docs/_build/doctrees/Structure.doctree
  76. BIN
      docs/_build/doctrees/articles/AgileWorkflowIntegration.doctree
  77. BIN
      docs/_build/doctrees/articles/Articles.doctree
  78. BIN
      docs/_build/doctrees/articles/AsynchronousAndCanonTests.doctree
  79. BIN
      docs/_build/doctrees/articles/BugSoup.doctree
  80. BIN
      docs/_build/doctrees/articles/SeleniumGridV4WithBaangt.doctree
  81. BIN
      docs/_build/doctrees/articles/StopTesting.doctree
  82. BIN
      docs/_build/doctrees/changelog.doctree
  83. BIN
      docs/_build/doctrees/docs/baangt-Plugin.doctree
  84. BIN
      docs/_build/doctrees/docs/baangt.TestCaseSequence.doctree
  85. BIN
      docs/_build/doctrees/docs/baangt.base.doctree
  86. BIN
      docs/_build/doctrees/environment.pickle
  87. BIN
      docs/_build/doctrees/index.doctree
  88. BIN
      docs/_build/doctrees/simpleExample.doctree
  89. 1 1
      docs/_build/html/.buildinfo
  90. 245 0
      docs/_build/html/BrowserDrivers.html
  91. 5 4
      docs/_build/html/DataFile.html
  92. 11 1
      docs/_build/html/Developer.html
  93. 2 1
      docs/_build/html/HistoryAndReasons.html
  94. 2 1
      docs/_build/html/Installation.html
  95. 33 30
      docs/_build/html/OverviewUsage.html
  96. 13 9
      docs/_build/html/ParametersConfigFile.html
  97. 17 11
      docs/_build/html/PlannedFeatures.html
  98. 32 1
      docs/_build/html/SimpleAPI.html
  99. 5 4
      docs/_build/html/Structure.html
  100. 0 0
      docs/_build/html/TestTypes.html

+ 2 - 1
.gitignore

@@ -14,4 +14,5 @@ __pycache__
 *.log
 *.pyo
 venv
-application.sublime-workspace
+application.sublime-workspace
+/.project

+ 18 - 1
README.md

@@ -2,4 +2,21 @@
 Please find the full documentation on [ReadTheDocs](https://baangt.readthedocs.io)
 
 # Further reading:
-Latest news on http://baangt.org for community edition and http://baangt.com for corporate environments.
+Latest news on http://baangt.org for community edition and http://baangt.com for corporate environments.
+
+
+ - donwload latest webdrivers in baangt/browserDrivers folder
+ - or if you run baangt and execute with TC.Browser = FF, then latest geckodriver will be downloaded.
+ 
+To run selenium grid 4 
+```bash
+$ java -jar /baangt/browserDrivers/selenium-server-4.0.0-alpha-5.jar standalone
+```
+
+Check http://localhost:4444/status
+
+Use examples/globals_grid4.json to test 
+
+TC.Browser: REMOTE_V4
+
+TC.BrowserAttributes: {'browserName': 'firefox', 'seleniumGridIp': '127.0.0.1', 'seleniumGridPort': '4444'}

BIN
SimpleTheInternet.xlsx


+ 0 - 19
TechSpecs/30 Ready/MULTIPROCESSING_REFACTOR.md

@@ -1,19 +0,0 @@
-# Multiprocessing
-In baangt.TestCaseSequenceMaster.py in method execute_parallel the class TestCaseSequenceParallel is called and executed.
-
-This works well on Mac and Ubuntu. But doesn't work on Windows.
-
-Also on Mac and Ubuntu the performance using this technique is not ideal, as all executations wait for the last task to 
-finish before they start a new iteration.
-
-# Goals
-Change from process based multiprocessing to thread based parallel processing (using standard module Threads instead of 
-Multiprocessing)
-
-# DoD:
-* Usage of `threading` and `Queue` instead of `multiprocessing` library to start parallel browsers and execute testcases
-in parallel.
-* After execution of Testcase latest data from Testcase (`TestdataDict`) is updated in `TestRun.py`
-* Functionality was tested locally on either Linux and/or Windows and/or Mac and results documented (e.g. Log-File 
-showing successful execution)
-* Pull request was created

+ 7 - 7
TechSpecs/30 Ready/randomValues.md

@@ -9,7 +9,7 @@ Example:
 * Names of business partners
 * Random text
 
-We want to provide an easily accessable feature for users of ```baangt``` to deal with this requirement without needing
+We want to provide an easily accessible feature for users of ```baangt``` to deal with this requirement without needing
 to develop code.
 
 ## Implementation
@@ -47,10 +47,10 @@ In Activity "Random" we need to store the resulting value in the field given in
 ## Example File
 An example File with explanations can be found in folder ``Examples``, filename ``Random.xlsx``
 
-## Scope / DOD
-* Implementation provided (in line with coding standards and PEP-8 conformity)
-* Functional test executed and passed (theoretically if values from ``Random.xlsx`` work, this should be enough)
-* Enhance existing documentation in docs-Folder in RST-Format
+## Scope / DOD (including effort estimation)
+* Implementation provided (in line with coding standards and PEP-8 conformity) (2 hours)
+* Functional test executed and passed (theoretically if values from ``Random.xlsx`` work, this should be enough) (1 hour)
+* Enhance existing documentation in docs-Folder in RST-Format (0,5 hours)
     * in this case in simpleExample.rst and SimpleAPI.rst
-* Unit-Tests in tests-folder providing reasonable coverage of the provided functionality
-* git commit to feature branch and pull request on Gogs created
+* Unit-Tests in tests-folder providing reasonable coverage (e.g. 80%) of the provided functionality (1 hour)
+* git commit to feature branch and pull request on Gogs created (no additional effort)

TechSpecs/30 Ready/CREATE_EXECUTABLE.md → TechSpecs/60 InProgress/CREATE_EXECUTABLE.md


+ 32 - 0
TechSpecs/60 InProgress/MULTIPROCESSING_REFACTOR.md

@@ -0,0 +1,32 @@
+# Multiprocessing
+In baangt.TestCaseSequenceMaster.py in method execute_parallel the class TestCaseSequenceParallel is called and executed.
+
+This works as designed on Mac and Ubuntu. But doesn't work on Windows.
+
+Also on Mac and Ubuntu the performance using this technique is not ideal, as all executions wait for the last task to 
+finish before they start a new iteration.
+
+# Goals
+Change from process based multiprocessing to thread based parallel processing (using standard module Threads instead of 
+Multiprocessing).
+
+Executions run in real parallel, for instance if we have 4 parallel executions, each one of them starts the next
+test case as soon as it was finished with the test case before.
+
+# Current implementation
+Current implementation is in baangt.TestCaseSequence.TestCaseSequenceMaster.py and from there calls 
+baangt.TestCaseSequenceParallel.py when parameter ``ParallelRuns`` has a value greater than 1.
+
+# Further documentation:
+baangt documentation is on https://baangt.readthedocs.io
+Repository is on https://gogs.earthsquad.global/athos/baangt
+
+# DoD (including effort indication):
+* Usage of `threading` and `Queue` instead of `multiprocessing` library to start parallel browsers and execute testcases
+in parallel. (1h)
+    * After execution of Testcase latest data from Testcase (`TestdataDict`) is updated in `TestRun.py` (=same behaviour as 
+        in the current implementation) (no effort)
+* Functionality was tested locally on either Linux and/or Windows and/or Mac and results documented (e.g. Log-File 
+showing successful execution) (2h)
+* Unit test cases in /tests for all touched methods created and successful (3h)
+* Pull request was created (no effort)

+ 79 - 0
TechSpecs/60 InProgress/NestedLoopsOfData.md

@@ -0,0 +1,79 @@
+# Current situation
+
+```baangt``` provides a simple way to run test automation with as little as one Microsoft Excel File (of course with
+reduced functionality, compared to full Excel format or ``baangtDB``). This works well as long as data for one test case
+can be read from one line in the data-file or data-tab (simple format).
+
+When we have nested data, it's not easily possible to process it, for example:
+
+* Sales order -> currently possible with baangt simple format. All good
+* Line items -> currently only possible by extending the fields of sales order with e.g. ```item_01_materialnumber```, 
+  ``item_01_quantity``, ``item_02_materialnumber``, ``item_02_quantity`` and so on.
+* Schedule items (e.g. 10 pieces in June, 20 pieces in July, etc.) -> with the current data structure not possible.
+
+# functional requirement
+
+We need to provide a simple way to deal with nested data structures like in the example above, without the user having
+to code. 
+
+# Solution approach
+
+## Provide JSON-Arrays in Excel cells.
+
+Enable ``baangt`` to read data from cells as arrays: 
+```
+[{line-item-number: 1,
+  material-number: 'baangtSticker'
+  quantity: 10
+  schedule: [{
+    date: '2020-03-20',
+    quantity: 5},
+    {
+    date: '2020-05-01',
+    quantity: 5}]
+ },
+ {line-item-number: 2,
+  material-number: 'baangtCourse'
+  quantity: 5
+ }]
+```
+
+## Provide possibility to write in separate tab (and interpret Tab into JSON)
+As the above mentioned way is definitely convenient to work with in Python, but is not at all user friendly, we should
+provide a function to read structured data from another Excel-Tab.
+
+If the column name of the current Excel-Column is identical to a tab-name in the same XLSX, read the tab and move all
+data from there, that is identical with the test case number, into the cell in the test case data as JSON (see above).
+
+## New command in testStepMaster.py
+
+We'll need a new command ``repeat``. Value1 is the column/field-name in testDataDict. The implementation of this command
+must loop over the json-array and process each test step until it reaches (the also new command) ``repeat-done``. It 
+shall automatically create a variable ``_enum`` into each loop (also nested) to know the current position.
+
+Nested ```repeat``` are possible as a JSON-String may include further lists of Dicts. For any command executed within 
+the ``repeat`` the ``Value1`` would read: ``<column_name>.<dict_Key>`` and for a nested entry: ``<column_name>.<dict_key>.<dict_key>``.
+
+## Export data 
+* Export format in XLSX shall contain the nested data as tabs with reference to test case line.
+* Export format in Database shall store the data in table ``<stage>_<object>`` (in above example e.g. ``test_schedule``)
+
+### Example:
+* REPEAT items
+* SETTEXT <some_xpath_to_material_field$(items._enum)> $(items.materialnumber)
+* SETTEXT <some_xpath_to_quantity_field$(items._enum)> $(items.quantity)
+* REPEAT items.schedule
+* SETTEXT <some_xpath_to_schedule_line$(items.schedule._enum)_date> $(items.schedule.date)
+* SETTEXT <some_xpath_to_schedule_line$(items.schedule._enum)_quantity> $(items.schedule.quantity)
+
+# DoD (including effort estimation (18 hours))
+
+* Implementation of JSON-Loops in TestStepMaster done and tested (2 hours)
+* Implementation of commands ```repeat``` and ``repeat-done`` incl. ``_enum`` (2 hours)
+* Implementation of Excel-Import from tabs into JSON-Field done and tested (2 hours)
+* Implementation of Excel-Export and database inserts for nested data (3 hours)
+* One working example file in /examples using 2 levels of nested data without other tabs (2 hours)
+* One working example file in /examples using 2 levels of nested data from other tabs (2 hours)
+* Updated documentation in /docs-Folder (1 hour)
+* Unit-Test coverage (in folder /tests) of 80% (for all committed/changed methods) (4 hours)
+* no critical linter errors or warnings (PEP-8 conformity of the code) (no additional effort)

TechSpecs/10 Ideas/PDFComparisonMicroService.md → TechSpecs/60 InProgress/PDFComparisonMicroService.md


+ 71 - 0
TechSpecs/60 InProgress/SaveResults2Database.md

@@ -0,0 +1,71 @@
+# Current situation
+
+Currently all test runs are already saved in a database. This happens in baangt.base.ExportResults.ExportResults.py in
+method exportToDataBase.
+
+Saving happens for:
+* Testrun name
+* Logfile name
+* Count of successful test cases
+* Count of not successful test cases
+* GlobalVars (JSON-String)
+* Name of data file
+
+This works well, but is not enough.
+
+# Goal
+We need to have more details about the test runs in the database, so that we can do more analytics, for instance:
+
+* Comparison of durations of the same test case throughout an extended period of time
+* Detect problematic services during longer running test cases
+
+The above mentioned analytics is **not** part of this TechSpec.
+
+# Implementation
+
+* Extend data persistence to save all data, that is currently exported in XLSX-Format also for database
+    (not as JSON into one field but as structured tables with columns).
+    * For that to work (and for other purposes) each object (TestRun, TestcaseSequence, TestCase) must have a unique key, that can be saved in the database in order to have key-columns for the database tables.
+        
+         Each table will have the UUID as key field.
+         
+    * Also testDataDict for each test case needs to be stored. Info: During a test run fields can be added. So before
+        saving testDataDict to an existing table of this testdata object, the structure needs to be checked and may need
+        additional fields than in a previous execution.
+    * Export UUID of test run (in summary tab) and test cases (in tab Output, Timing and Network) in XLSX-Export
+         
+* Add capability to save test case result data in additional export format.
+    * When a column of testDataDict is in format ``$<objectname>-<fieldname>``:
+        * For XLSX-Output:
+           * Add a new tab to MS Excel and fill in the data into this tab. Tab-name is ``<stage>_<objectname>``. 
+           * Create columns in the header: ``<stage>``, ``<uuid>`` of the test case, ``[<fieldname>]``
+           * For each entry in testDataDict write ``stage``, ``uuid``,``<fieldname>`` into the appropriate column 
+             in this Excel-Tab.
+        * Into the database:
+            * look for a table ``<stage>-<objectname>``.
+            * If it exsits, check if ``[<fieldname>]`` are found in the structure
+            * If it doesn't exist, create the table with structure ``uuid``, ``[<fieldname>]``
+            * If needed, extend structure
+            * Add also ``uuid`` of the test case.
+            * Append entries similarly to XLSX above.
+            
+This will lead to double saving of the same data, once in testDataDict (e.g. in XLSX in Tab Output) and once in a separate
+tab ``<stage>_<objectname>``. The reason for that is to provide a simpler way for users to extract such data from multiple
+XLSX-Files into one database, in case they don't want to or can't use the built-in database storage.
+
+# Examples for using the additionally stored data:
+* Creating master data records (e.g. customers) in a certain stage (e.g. Test, Pre-Quality, Final-Quality, Migration, etc.)
+  and re-using this data in other test cases (e.g. customer orders). In this case the user would first run the test cases
+  that create master data, then Cross-reference the results in their customer order data records for this stage,
+  and finally run those test cases (the cross-referencing happens in XLSX, for instance using VLOOKUP or VBA). 
+            
+# DoD (incl. rough effort estimation)
+
+* XLSX and Database are populated with the above mentioned data (new fields, new Tables/Tabs) (6-8 hours)
+* STAGE-variable existing in all TestRuns (default value = ``Test``). Hint: Can be set in HandleDatabase.py in __init__ 
+  as e.g. GC.EXECUTION_STAGE = GC.EXECUTION_STAGE_TEST (0,5 hours)
+* One working example file in /examples using multiple fields in format ``$<objectname>-<fieldname>`` including 
+  output file committed to examples-folder. (2 hours)
+* Updated documentation in /docs-Folder (1 hour)
+* Unit-Test coverage (in folder /tests) of 80% (for all committed/changed methods) (4 hours)
+* no critical linter errors or warnings (PEP-8 conformity of the code) (no additional effort)

+ 1 - 1
TechSpecs/30 Ready/UI_ShowStatusOfTestrun.md

@@ -1,4 +1,4 @@
-# Situation
+# Situation (Munish)
 
 Right now when you start ``baangt`` interactive starter, choose a testrun and globals file and execute the testrun there's
 a log either in the console or in your IDE (depending from where you start it), but directly in the UI you don't see

+ 2 - 0
baangt.py

@@ -1,3 +1,5 @@
+from gevent import monkey
+monkey.patch_all()
 from baangt.base.CliAndInteractive import run
 from multiprocessing import freeze_support
 

+ 3 - 0
baangt/TestCase/TestCaseMaster.py

@@ -80,5 +80,8 @@ class TestCaseMaster:
                 self.kwargs[GC.KWARGS_DATA][GC.SCREENSHOTS] = self.kwargs[GC.KWARGS_DATA][GC.SCREENSHOTS] + '\n' +\
                                                               self.browser.takeScreenshot()
 
+        if not self.kwargs[GC.KWARGS_DATA][GC.TESTCASESTATUS]:
+            self.kwargs[GC.KWARGS_DATA][GC.TESTCASESTATUS] = GC.TESTCASESTATUS_SUCCESS
+
         self._checkAndSetTestcaseStatusIfFailExpected()
 

BIN
baangt/TestCase/TestCaseMaster.pyo


BIN
baangt/TestCase/__init__.pyo


+ 50 - 51
baangt/TestCaseSequence/TestCaseSequenceMaster.py

@@ -9,6 +9,9 @@ import time
 from datetime import datetime
 import sys
 import logging
+import gevent
+import gevent.queue
+import gevent.pool
 
 logger = logging.getLogger("pyC")
 
@@ -58,62 +61,58 @@ class TestCaseSequenceMaster:
         # In this case we need to request them, because the Testcases will run in their own
         # Processes
         parallelInstances = int(parallelInstances)
-        browserInstances = {}
-        for n in range(0, int(parallelInstances)):
+
+        # Browser instances
+        browsers = []
+        results = gevent.queue.Queue()
+        records = gevent.queue.Queue()
+
+        for n, record in self.dataRecords.items():
+            records.put((n, record))
+
+        def single_thread(sequenceNumber):
             # fixme: Browser should come from Testcase definition - not hardcoded. It's not that easy, as we might have many
             # fixme: Testcases, some Browser, some API and we might even have different browsers. For now we'll only
             # fixme: take Browser from globals-file
+            # create browser
+
             lBrowserName = self.testRunInstance.globalSettings.get("TC.Browser", GC.BROWSER_FIREFOX)
             lBrowserAttributes = self.testRunInstance.globalSettings.get("TC." + GC.BROWSER_ATTRIBUTES, None)
-            browserInstances[n] = self.testRunInstance.getBrowser(browserInstance=n,
-                                                                  browserName=lBrowserName,
-                                                                  browserAttributes=lBrowserAttributes)
-
-        processes = {}
-        processExecutions = {}
-        resultQueue = multiprocessing.Queue()
-
-        numberOfRecords = len(self.dataRecords)
-        for n in range(0, numberOfRecords, parallelInstances):
-            for x in range(0, parallelInstances):
-                if self.dataRecords.get(n + x):
-                    logger.debug(f"starting Process and Executions {x}. Value of n+x is {n + x}, "
-                                 f"Record = {str(self.dataRecords[n + x])[0:50]}")
-                    self.kwargs[GC.KWARGS_DATA] = self.dataRecords[n+x]
-                    # Prints the first 5 fields of the data record into the log:
-                    logger.info(f"Starting parallel execution with TestRecord {n+x}, Details: " +
-                        str({k: self.kwargs[GC.KWARGS_DATA][k] for k in list(self.kwargs[GC.KWARGS_DATA])[0:5]}))
-                    self.kwargs[GC.KWARGS_BROWSER] = browserInstances[x]
-                    processes[x] = TestCaseSequenceParallel(sequenceNumber=x,
-                                                            tcNumber=n + x,
-                                                            testcaseSequence=self.testCases,
-                                                            **self.kwargs)
-                    processExecutions[x] = multiprocessing.Process(target=processes[x].one_sequence,
-                                                                   args=(resultQueue,))
-                else:
-                    # This is the case when we have e.g. 4 parallel runs and 5 testcases,
-                    # First iteration: all 4 are used. Second iteration: only 1 used, 3 are empty.
-                    if processExecutions.get(x):
-                        processExecutions.pop(x)
-
-            for x in range(0, parallelInstances):
-                logger.info(f"starting execution of parallel instance {x}")
-                if processExecutions.get(x):
-                    processExecutions[x].start()
-
-            for x in range(0, parallelInstances):
-                if processExecutions.get(x):
-                    # Queue should be filled by now - take entries into Testrun-instance:
-                    while not resultQueue.empty():
-                        resultDictList = resultQueue.get()
-                        for recordNumber, dataRecordAfterExecution in resultDictList[0].items():
-                            self.testRunInstance.setResult(recordNumber, dataRecordAfterExecution)
-                        for sequenceNumber, tcNumberAndTestEnd in resultDictList[1].items():
-                            self.testRunInstance.append2DTestCaseEndDateTimes(sequenceNumber, tcNumberAndTestEnd)
-
-                    # Quit the running parallel process:
-                    logger.info(f"Stopping parallel instance {x}")
-                    processExecutions[x].join()
+            browser = self.testRunInstance.getBrowser(browserInstance=sequenceNumber,
+                                            browserName=lBrowserName,
+                                            browserAttributes=lBrowserAttributes)
+                                            
+            # Consume records
+            while not records.empty():
+                n, record = records.get()
+                kwargs = {
+                    GC.KWARGS_DATA: record,
+                    GC.KWARGS_BROWSER: browser,
+                    **self.kwargs
+                }
+
+                logger.info(f"Starting parallel execution with TestRecord {n}, Details: " +
+                    str({k: kwargs[GC.KWARGS_DATA][k] for k in list(kwargs[GC.KWARGS_DATA])[0:5]}))
+
+                process = TestCaseSequenceParallel(tcNumber=n,
+                                                    sequenceNumber=sequenceNumber,
+                                                    testcaseSequence=self.testCases,
+                                                    **kwargs)
+                process.one_sequence(results)
+
+
+        # Create and runconcurrent threads
+        threads = gevent.joinall([
+            gevent.spawn(single_thread, num) for num in range(parallelInstances)
+        ])
+
+        # after joining all threads
+        while not results.empty():
+            result = results.get()
+            for recordNumber, dataRecordAfterExecution in result[0].items():
+                self.testRunInstance.setResult(recordNumber, dataRecordAfterExecution)
+            for sequenceNumber, tcNumberAndTestEnd in result[1].items():
+                self.testRunInstance.append2DTestCaseEndDateTimes(sequenceNumber, tcNumberAndTestEnd)
 
     def execute(self):
         # Execute all Testcases:

BIN
baangt/TestCaseSequence/TestCaseSequenceMaster.pyo


+ 5 - 10
baangt/TestCaseSequence/TestCaseSequenceParallel.py

@@ -4,24 +4,24 @@ from baangt.TestSteps import Exceptions
 from baangt.base import GlobalConstants as GC
 from datetime import datetime
 import time
+import gevent.queue
 logger = logging.getLogger("pyC")
 
 
 class TestCaseSequenceParallel:
-    def __init__(self, sequenceNumber, tcNumber, testcaseSequence=None, **kwargs):
-        self.manager = multiprocessing.Manager()
-        self.process_list = self.manager.list()
+    def __init__(self, sequenceNumber: int, tcNumber: int, testcaseSequence=None, **kwargs):
         self.sequenceNumber = sequenceNumber
         self.dataRecord = kwargs.get(GC.KWARGS_DATA)
         self.tcNumber = tcNumber
         self.testcaseSequence = testcaseSequence
         self.kwargs = kwargs
 
-    def one_sequence(self, resultQueue: multiprocessing.Queue):
+    def one_sequence(self, results: gevent.queue.Queue):
         dataRecord = self.dataRecord
         currentRecordNumber = self.tcNumber
         testcaseSequence = self.testcaseSequence
         parallelizationSequenceNumber = self.sequenceNumber
+        
         logger.info(f"Starting one_sequence with SequenceNumber = {parallelizationSequenceNumber}, "
                     f"CurrentRecordNumber is {currentRecordNumber}")
 
@@ -34,14 +34,9 @@ class TestCaseSequenceParallel:
                                                                                 GC.STRUCTURE_TESTCASE,
                                                                                 **self.kwargs)
 
-
         except Exceptions.baangtTestStepException as e:
             logger.critical(f"Unhandled Error happened in parallel run {parallelizationSequenceNumber}: " + str(e))
             dataRecord[GC.TESTCASESTATUS] = GC.TESTCASESTATUS_ERROR
         finally:
-            # the result must be pushed into the queue:
-            logger.debug(
-                f"Starting to Put value in Queue {currentRecordNumber}. Len of datarecord: {len(str(dataRecord))}")
             d_t = datetime.fromtimestamp(time.time())
-            resultQueue.put([{self.tcNumber: dataRecord}, {self.sequenceNumber:  [self.tcNumber, d_t]}])
-            logger.debug(f"Finished putting Value i Queue for TC {currentRecordNumber}")
+            results.put([{self.tcNumber: dataRecord}, {self.sequenceNumber:  [self.tcNumber, d_t]}])

BIN
baangt/TestCaseSequence/TestCaseSequenceParallel.pyo


BIN
baangt/TestCaseSequence/__init__.pyo


BIN
baangt/TestSteps/AddressCreation.pyo


BIN
baangt/TestSteps/Exceptions.pyo


+ 2 - 0
baangt/TestSteps/TestStepMaster.py

@@ -87,6 +87,8 @@ class TestStepMaster:
                 self.browserSession.handleIframe(lLocator)
             elif lActivity == "CLICK":
                 self.browserSession.findByAndClick(xpath=xpath, css=css, id=id, timeout=lTimeout)
+            elif lActivity == "PAUSE":
+                self.browserSession.sleep(sleepTimeinSeconds=lValue)
             elif lActivity == "IF":
                 if self.ifActive:
                     raise BaseException("No nested IFs at this point, sorry...")

BIN
baangt/TestSteps/TestStepMaster.pyo


BIN
baangt/TestSteps/__init__.pyo


BIN
baangt/__init__.pyo


BIN
baangt/base/ApiHandling.pyo


+ 69 - 37
baangt/base/BrowserHandling/BrowserHandling.py

@@ -37,6 +37,7 @@ class BrowserDriver:
     - javaScript: to pass JS directly to the browser
     - takeScreenshot: yes, that.
     """
+
     def __init__(self, timing=None, screenshotPath=None):
         self.driver = None
         self.iFrame = None
@@ -75,23 +76,23 @@ class BrowserDriver:
             GC.BROWSER_EDGE: webdriver.Edge,
             GC.BROWSER_REMOTE: webdriver.Remote}
 
-        if browserName in browserNames:
-            GeckoExecutable = "geckodriver"
-            ChromeExecutable = "chromedriver"
+        GeckoExecutable = "geckodriver"
+        ChromeExecutable = "chromedriver"
 
-            if 'NT' in os.name.upper():
-                GeckoExecutable = GeckoExecutable + ".exe"
-                ChromeExecutable = ChromeExecutable + ".exe"
+        if 'NT' in os.name.upper():
+            GeckoExecutable = GeckoExecutable + ".exe"
+            ChromeExecutable = ChromeExecutable + ".exe"
 
+        lCurPath = Path(os.getcwd())
+        lCurPath = lCurPath.joinpath("browserDrivers")
 
-            lCurPath = Path(os.getcwd())
-            lCurPath = lCurPath.joinpath("browserDrivers")
+        if browserName in browserNames:
 
             browserProxy = kwargs.get('browserProxy')
             browserInstance = kwargs.get('browserInstance', 'unknown')
             if browserName == GC.BROWSER_FIREFOX:
                 lCurPath = lCurPath.joinpath(GeckoExecutable)
-                if not(os.path.isfile(str(lCurPath))):
+                if not (os.path.isfile(str(lCurPath))):
                     self.downloadDriver(browserName)
 
                 profile = None
@@ -111,14 +112,16 @@ class BrowserDriver:
                 lCurPath = lCurPath.joinpath(ChromeExecutable)
                 if not (os.path.isfile(str(lCurPath))):
                     self.downloadDriver(browserName)
-                self.driver = browserNames[browserName](chrome_options=self.__createBrowserOptions(browserName=browserName,
-                                                                                            desiredCapabilities=desiredCapabilities,
-                                                                                            browserProxy=browserProxy),
-                                                        executable_path=self.__findBrowserDriverPaths(ChromeExecutable))
+                self.driver = browserNames[browserName](
+                    chrome_options=self.__createBrowserOptions(browserName=browserName,
+                                                               desiredCapabilities=desiredCapabilities,
+                                                               browserProxy=browserProxy),
+                    executable_path=self.__findBrowserDriverPaths(ChromeExecutable))
                 browserProxy.new_har("baangt-chrome-{}".format(browserInstance),
                                      options={'captureHeaders': True, 'captureContent': True}) if browserProxy else None
             elif browserName == GC.BROWSER_EDGE:
-                self.driver = browserNames[browserName](executable_path=self.__findBrowserDriverPaths("msedgedriver.exe"))
+                self.driver = browserNames[browserName](
+                    executable_path=self.__findBrowserDriverPaths("msedgedriver.exe"))
             elif browserName == GC.BROWSER_SAFARI:
                 # SAFARI doesn't provide any options, but desired_capabilities.
                 # Executable_path = the standard safaridriver path.
@@ -131,6 +134,35 @@ class BrowserDriver:
                                                                                             desiredCapabilities=desiredCapabilities),
                                                         command_executor='http://localhost:4444/wd/hub',
                                                         desired_capabilities=desiredCapabilities)
+        elif browserName == GC.BROWSER_REMOTE_V4:
+            desired_capabilities = eval(desiredCapabilities)
+            if 'seleniumGridIp' in desired_capabilities.keys():
+                seleniumGridIp = desired_capabilities['seleniumGridIp']
+                del desired_capabilities['seleniumGridIp']
+            else:
+                seleniumGridIp = '127.0.0.1'
+
+            if 'seleniumGridPort' in desired_capabilities.keys():
+                seleniumGridPort = desired_capabilities['seleniumGridPort']
+                del desired_capabilities['seleniumGridPort']
+            else:
+                seleniumGridPort = '4444'
+
+            if not 'browserName' in desired_capabilities.keys():
+                desired_capabilities['browserName'] = 'firefox'
+
+            if desired_capabilities['browserName'] == 'firefox':
+                lCurPath = lCurPath.joinpath(GeckoExecutable)
+                if not (os.path.isfile(str(lCurPath))):
+                    self.downloadDriver(GC.BROWSER_FIREFOX)
+            elif desired_capabilities['browserName'] == 'chrome':
+                lCurPath = lCurPath.joinpath(ChromeExecutable)
+                if not (os.path.isfile(str(lCurPath))):
+                    self.downloadDriver(GC.BROWSER_CHROME)
+
+            serverUrl = 'http://' + seleniumGridIp + ':' + seleniumGridPort
+
+            self.driver = webdriver.Remote(command_executor=serverUrl, desired_capabilities=desired_capabilities)
         else:
             raise SystemExit("Browsername unknown")
 
@@ -154,7 +186,7 @@ class BrowserDriver:
         logger.debug(f"Path for BrowserDrivers: {lCurPath}")
         return str(lCurPath)
 
-    def slowExecutionToggle(self, newSlowExecutionWaitTimeInSeconds = None):
+    def slowExecutionToggle(self, newSlowExecutionWaitTimeInSeconds=None):
         """
         SlowExecution can be set in globals or by the teststep. It's intended use is debugging or showcasing a testcases
         functionality.
@@ -173,7 +205,6 @@ class BrowserDriver:
 
         return self.slowExecution
 
-
     def __createBrowserOptions(self, browserName, desiredCapabilities, browserProxy=None):
         """
         Translates desired capabilities from the Testrun (or globals) into specific BrowserOptions for the
@@ -345,7 +376,7 @@ class BrowserDriver:
                 elif self.element.tag_name == 'input':
                     #  element is of type <input />
                     return self.element.get_property('value')
-                
+
             except Exception as e:
                 logger.debug(f"Exception during findByAndWaitForValue, but continuing {str(e)}, "
                              f"Locator: {self.locatorType} = {self.locator}")
@@ -392,14 +423,14 @@ class BrowserDriver:
         return self.findByAndSetText(id=id, css=css, xpath=xpath, class_name=class_name, value=value, iframe=iframe,
                                      timeout=timeout)
 
-    def findByAndSetTextValidated(self,id = None,
-                       css = None,
-                       xpath = None,
-                       class_name = None,
-                       value = None,
-                       iframe = None,
-                       timeout = 60,
-                       retries = 5):
+    def findByAndSetTextValidated(self, id=None,
+                                  css=None,
+                                  xpath=None,
+                                  class_name=None,
+                                  value=None,
+                                  iframe=None,
+                                  timeout=60,
+                                  retries=5):
         """
         This is a method not recommended to be used regularly. Sometimes (especially with Angular Frontends) it gets
         pretty hard to set a value into a field. Chrome, but also FF will show the value, but the DOM will not have it.
@@ -412,7 +443,6 @@ class BrowserDriver:
         self.findBy(id=id, css=css, xpath=xpath, class_name=class_name, iframe=iframe, timeout=timeout)
 
         while self.element.text != value and self.element.get_property("value") != value and tries < retries:
-
             self._log(logging.DEBUG, f"Verified trying of SetText - iteration {tries} of {retries}")
 
             self.findByAndForceText(id=id, css=css, xpath=xpath, class_name=class_name, iframe=iframe,
@@ -429,7 +459,7 @@ class BrowserDriver:
         """
         self.element.submit()
 
-    def findByAndClick(self, id = None, css=None, xpath=None, class_name=None, iframe=None, timeout=20, optional=False):
+    def findByAndClick(self, id=None, css=None, xpath=None, class_name=None, iframe=None, timeout=20, optional=False):
         """
         Execute a Click on an element identified by it's locator.
         @return wasSuccessful says, whether the element was found.
@@ -571,7 +601,7 @@ class BrowserDriver:
                 elif xpath:
                     # visibility of element sometimes not true, but still clickable. If we tried already
                     # 2 times with visibility, let's give it one more try with Presence of element
-                    if lLoopCount > 2:
+                    if lLoopCount > 1:
                         self._log(logging.INFO, "Tried 2 times to find visible element, now trying presence "
                                                 f"of element instead, XPATH = {xpath}")
                         self.element = driverWait.until(ec.presence_of_element_located((By.XPATH, xpath)))
@@ -607,13 +637,13 @@ class BrowserDriver:
 
         return wasSuccessful
 
-    def findWaitNotVisible(self, css=None, xpath=None, id=None, timeout = 90, optional = False):
+    def findWaitNotVisible(self, css=None, xpath=None, id=None, timeout=90, optional=False):
         """
         You'd use this method when you wait for an element to disappear, for instance Angular Spinner or a popup
         to disapear before you continue with your script in the main screen.
 
         """
-        self._log(logging.DEBUG, "Waiting for Element to disappear", **{"xpath":xpath, "timeout":timeout})
+        self._log(logging.DEBUG, "Waiting for Element to disappear", **{"xpath": xpath, "timeout": timeout})
         time.sleep(0.5)
 
         stillHere = True
@@ -636,7 +666,8 @@ class BrowserDriver:
                 self._log(logging.DEBUG, f"Element was gone after {format(elapsed, '.2f')} seconds")
                 return
 
-        raise Exceptions.baangtTestStepException(f"Element still here after {timeout} seconds. Locator: xpath={xpath}, id={id}")
+        raise Exceptions.baangtTestStepException(
+            f"Element still here after {timeout} seconds. Locator: xpath={xpath}, id={id}")
 
     @staticmethod
     def sleep(sleepTimeinSeconds):
@@ -688,12 +719,14 @@ class BrowserDriver:
                 raise Exceptions.baangtTestStepException(e)
             except NoSuchWindowException as e:
                 raise Exceptions.baangtTestStepException(e)
-            elapsed = time.time()-begin
+            elapsed = time.time() - begin
 
         if optional:
-            logger.debug(f"Action not possible after {timeout} s, Locator: {self.locatorType}: {self.locator}, but flag 'optional' is set")
+            logger.debug(
+                f"Action not possible after {timeout} s, Locator: {self.locatorType}: {self.locator}, but flag 'optional' is set")
         else:
-            raise Exceptions.baangtTestStepException(f"Action not possible after {timeout} s, Locator: {self.locatorType}: {self.locator}")
+            raise Exceptions.baangtTestStepException(
+                f"Action not possible after {timeout} s, Locator: {self.locatorType}: {self.locator}")
 
     def goToUrl(self, url):
         self._log(logging.INFO, f'GoToUrl:{url}')
@@ -714,12 +747,11 @@ class BrowserDriver:
         except Exception as e:
             self._log(logging.WARNING, f"Tried to go back in history, didn't work with error {e}")
 
-
     def javaScript(self, jsText):
         """Execute a given JavaScript in the current Session"""
         self.driver.execute_script(jsText)
 
-    def downloadDriver(self,browserName):
+    def downloadDriver(self, browserName):
         path = Path(os.getcwd())
         path = path.joinpath("browserDrivers")
         tar_url = ''
@@ -751,7 +783,7 @@ class BrowserDriver:
 
             if tar_url != '':
                 path_zip = path.joinpath(GC.GECKO_DRIVER.replace('exe', 'tar.gz'))
-                filename, headers = urlretrieve(tar_url,path_zip)
+                filename, headers = urlretrieve(tar_url, path_zip)
                 tar = tarfile.open(filename, "r:gz")
                 tar.extractall(path)
                 tar.close()

BIN
baangt/base/BrowserHandling/BrowserHandling.pyo


BIN
baangt/base/BrowserHandling/__init__.pyo


BIN
baangt/base/BrowserHandling/hookImpls.pyo


+ 10 - 4
baangt/base/CliAndInteractive.py

@@ -2,12 +2,14 @@ import sys, getopt
 from baangt.base.Utils import utils
 from baangt.ui.ui import UI
 from baangt import plugin_manager
+import baangt.base.GlobalConstants as GC
 
 def print_args():
     print("""
 Call: python baangt.py --parameters 
        --run=<Existing, predefined Name of a TestRun (XLSX or .JSON-File incl. Path)>
        --globals=<path to JSON-File containing global Settings. If omitted, will look for globals.json in the current directory>
+       --reloadDrivers=<anyValue> : This command will replace existing browser drivers (Chrome/Firefox) with latest versions
 
  Suggested for standard use:
    python baangt.py --run="Franzi4711.xlsx": Will run a Testrun Franzi4711.xlsx
@@ -23,7 +25,8 @@ def args_read(l_search_parameter):
 
     try:
         opts, args = getopt.getopt(l_args, "", ["run=",
-                                                "globals="
+                                                "globals=",
+                                                "reloadDrivers="
                                                 ])
     except getopt.GetoptError as err_det:
         print("Error in reading parameters:" + str(err_det))
@@ -54,9 +57,6 @@ def callTestrun(testRunFile):
     else:
         sys.exit(f"Unknown Filetype - should be XLSX or JSON: {testRunFile}")
 
-
-
-
 def run():
 
     print_args()
@@ -65,6 +65,12 @@ def run():
     if testRunFile:
         print(f"Starting Testrun: {testRunFile}")
         callTestrun(testRunFile)
+    elif args_read("reloadDrivers"):
+        from baangt.base.BrowserHandling.BrowserHandling import BrowserDriver
+        lDriver = BrowserDriver()
+        lDriver.downloadDriver(GC.BROWSER_FIREFOX)
+        lDriver.downloadDriver(GC.BROWSER_CHROME)
+        print("Latest versions of drivers for Firefox and Chrome were downloaded")
     else:
         UI()
 

BIN
baangt/base/CliAndInteractive.pyo


BIN
baangt/base/CustGlobalConstants.pyo


BIN
baangt/base/DataBaseORM.pyo


BIN
baangt/base/ExportResults/ExportResults.pyo


BIN
baangt/base/ExportResults/__init__.pyo


BIN
baangt/base/ExportResults/hookImpls.pyo


+ 2 - 1
baangt/base/GlobalConstants.py

@@ -28,6 +28,7 @@ BROWSER_CHROME = "CHROME"
 BROWSER_SAFARI = "SAFARI"
 BROWSER_EDGE = "EDGE"
 BROWSER_REMOTE = 'REMOTE'
+BROWSER_REMOTE_V4 = 'REMOTE_V4'
 BROWSER_MODE_HEADLESS = "HEADLESS"
 BROWSER_ATTRIBUTES = "BrowserAttributes"
 
@@ -60,7 +61,7 @@ EXECUTION_DONTCLOSEBROWSER = "dontCloseBrowser"
 EXECUTION_SLOW = "slowExecution"
 EXECUTION_NETWORK_INFO = 'NetworkInfo'
 
-EXPORT_FORMAT = "Export Format"
+EXPORT_FORMAT = "ExportFormat"
 EXP_FIELDLIST = "Fieldlist"
 EXP_XLSX = "XLSX"
 EXP_CSV = "CSV"

BIN
baangt/base/GlobalConstants.pyo


BIN
baangt/base/HandleDatabase.pyo


BIN
baangt/base/TestRun/TestRun.pyo


BIN
baangt/base/TestRun/__init__.pyo


BIN
baangt/base/TestRun/hookImpls.pyo


BIN
baangt/base/TestRunExcelImporter.pyo


BIN
baangt/base/TestRunUtils.pyo


BIN
baangt/base/Timing/Timing.pyo


BIN
baangt/base/Timing/__init__.pyo


BIN
baangt/base/Timing/hookImpls.pyo


BIN
baangt/base/Utils.pyo


BIN
baangt/base/__init__.pyo


BIN
baangt/hookSpecs.pyo


BIN
baangt/ui/ImportKatalonRecorder.pyo


BIN
baangt/ui/__init__.pyo


BIN
baangt/ui/ui.pyo


+ 0 - 5
baangtExec.py

@@ -1,5 +0,0 @@
-from baangt.base.CliAndInteractive import run
-from multiprocessing import freeze_support
-
-freeze_support()
-run()

+ 2 - 0
baangtIA.py

@@ -1,3 +1,5 @@
+from gevent import monkey
+monkey.patch_all()
 from baangt.base.CliAndInteractive import run
 from multiprocessing import freeze_support
 

+ 11 - 6
ubuntu/baangt.spec

@@ -1,13 +1,18 @@
 # -*- mode: python ; coding: utf-8 -*-
+import sys
+sys.setrecursionlimit(5000)
 
 block_cipher = None
 
 
-a = Analysis(['../baangtExec.py'],
-             pathex=['ubuntu'],
+a = Analysis(['baangtIA.py'],
+             pathex=['/Users/bernhardbuhl/git/baangt'],
              binaries=[],
-             datas=[('../baangt/ressources/baangtLogo2020Small.png', 'ressources'), ('../browserDrivers/geckodriver', 'geckodriver')],
-             hiddenimports=[],
+             datas=[('browserDrivers/geckodriver', 'geckodriver'),
+                       ('browserDrivers/chromedriver', 'chromedriver'),
+                       ('browserDrivers/geckodriver.exe', 'geckodriver.exe'),
+                       ('browserDrivers/chromedriver.exe', 'chromedriver.exe')],
+             hiddenimports=['selenium'],
              hookspath=[],
              runtime_hooks=[],
              excludes=[],
@@ -21,7 +26,7 @@ exe = EXE(pyz,
           a.scripts,
           [],
           exclude_binaries=True,
-          name='baangt',
+          name='baangtIA',
           debug=False,
           bootloader_ignore_signals=False,
           strip=False,
@@ -34,4 +39,4 @@ coll = COLLECT(exe,
                strip=False,
                upx=True,
                upx_exclude=[],
-               name='baangt')
+               name='baangtIA')

BIN
browserDrivers/chromedriver.exe


BIN
browserDrivers/chromedriver_78


BIN
browserDrivers/geckodriver


BIN
browserDrivers/geckodriver.exe


BIN
browserDrivers/msedgedriver.exe


+ 0 - 0
browsermob-proxy/bin/browsermob-proxy


+ 10 - 0
docs/BrowserDrivers.rst

@@ -11,6 +11,16 @@ As you work with ``baangt`` for a longer time your browsers might be updated. If
 version of browser driver, you can simply delete the existing driver in ``baangt/BrowserDrivers/`` and on the next start
 ``baangt`` will automatically download the latest version.
 
+Alternative version:
+^^^^^^^^^^^^^^^^^^^^
+
+If you start baangt with the following syntax from the command line, it will download the latest drivers (Chrome and
+Firefox) automatically:
+
+```python3 baangt.py --reloadDrivers=True```
+
+It will overwrite existing versions.
+
 Older releases of browser drivers
 ---------------------------------
 

+ 1 - 1
docs/ParametersConfigFile.rst

@@ -27,7 +27,7 @@ for instance to slowly retest a single testrecord or to not close the browser af
      - When set to ``true``, the browser will stop for a short time after each command, so that you can also visually see what the browser is doing
    * - ``dontCloseBrowser``
      - When the browser or script finds an error, it usually takes a screenshot and moves on to the next testcase. With this setting to ``True`` the browser session will stop right at the error.
-   * - ``TC.BrowserOptions``
+   * - ``TC.BrowserAttributes``
      - Set the value to ``{'HEADLESS': 'True'}`` to run Chrome/Firefox in headless mode.
    * - ``TC.Lines``
      - Which lines from datafile to process.

+ 8 - 5
docs/PlannedFeatures.rst

@@ -4,15 +4,17 @@ We implement all features for 3 operating Systems (Mac, Windows, Debian Linux an
 
 Short/Medium term features
 ---------------------------
-* Refactoring of parallel processing on a single computer (2020.03)
-* Executables on Mac, Linux and Windows (2020.03)
+* Refactoring of parallel processing on a single computer (2020.03) --> Done
+* Executables on Mac, Linux and Windows (2020.03) --> Done
 * Nicer interactive UI-Starter (2020.03)
     * Phase 1 done 2020.02
-    * Phase 2 (UI-elements) (2020.03)
+    * Phase 2 (UI-elements) (2020.03) --> will move to 2020.04 RC5
     * Provide live statistics (2020.04)
-* Double Opt-In Automation (2020.03)
+* Double Opt-In Automation (2020.03) --> will move to 2020.04 RC6
 * Support for Selenium Grid V4 (2020.04)
 * Better support for multiple sources (e.g. multiple XLSX) of test data (2020.04)
+* Better support to store test data output to database and export files (2020.04)
+* Support for Appium integration (2020.04)
 * Katalon Importer/Converter as Webservice (2020.04)
 
 Features for later
@@ -23,7 +25,8 @@ Features for later
 * Integration with Atlassian Confluence (for Testcase and Testrun definitions)
 * Integration with Atlassian Confluence (to publish results of testruns)
 * Integration with MS Teams to publish results of Testruns
-* Grafana Board for Flask-Version
+* Integration with Telegram to publish results of Testruns
+* Grafana Board for baangtDB
 * Better support for oData V4.0 (similar to SOAP)
 * Support for GraphQL via Graphene
 

BIN
docs/_build/doctrees/BrowserDrivers.doctree


BIN
docs/_build/doctrees/DataFile.doctree


BIN
docs/_build/doctrees/Developer.doctree


BIN
docs/_build/doctrees/OverviewUsage.doctree


BIN
docs/_build/doctrees/ParametersConfigFile.doctree


BIN
docs/_build/doctrees/PlannedFeatures.doctree


BIN
docs/_build/doctrees/SimpleAPI.doctree


BIN
docs/_build/doctrees/Structure.doctree


BIN
docs/_build/doctrees/articles/AgileWorkflowIntegration.doctree


BIN
docs/_build/doctrees/articles/Articles.doctree


BIN
docs/_build/doctrees/articles/AsynchronousAndCanonTests.doctree


BIN
docs/_build/doctrees/articles/BugSoup.doctree


BIN
docs/_build/doctrees/articles/SeleniumGridV4WithBaangt.doctree


BIN
docs/_build/doctrees/articles/StopTesting.doctree


BIN
docs/_build/doctrees/changelog.doctree


BIN
docs/_build/doctrees/docs/baangt-Plugin.doctree


BIN
docs/_build/doctrees/docs/baangt.TestCaseSequence.doctree


BIN
docs/_build/doctrees/docs/baangt.base.doctree


BIN
docs/_build/doctrees/environment.pickle


BIN
docs/_build/doctrees/index.doctree


BIN
docs/_build/doctrees/simpleExample.doctree


+ 1 - 1
docs/_build/html/.buildinfo

@@ -1,4 +1,4 @@
 # Sphinx build info version 1
 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: 98e25ace4729fecfc9213be5ad9d34a1
+config: 837d53094322b956a4c0d61a5bac9771
 tags: 645f666f9bcd5a90fca523b33c5a78b7

+ 245 - 0
docs/_build/html/BrowserDrivers.html

@@ -0,0 +1,245 @@
+
+
+<!DOCTYPE html>
+<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
+<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
+<head>
+  <meta charset="utf-8">
+  
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  
+  <title>Handling of Browser Drivers &mdash; baangt 2020.3.0.rc4 documentation</title>
+  
+
+  
+  
+  
+  
+
+  
+  <script type="text/javascript" src="_static/js/modernizr.min.js"></script>
+  
+    
+      <script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+        <script type="text/javascript" src="_static/language_data.js"></script>
+    
+    <script type="text/javascript" src="_static/js/theme.js"></script>
+
+    
+
+  
+  <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
+  <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="next" title="Not Exactly Documentation" href="articles/Articles.html" />
+    <link rel="prev" title="Future Features" href="PlannedFeatures.html" /> 
+</head>
+
+<body class="wy-body-for-nav">
+
+   
+  <div class="wy-grid-for-nav">
+    
+    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
+      <div class="wy-side-scroll">
+        <div class="wy-side-nav-search" >
+          
+
+          
+            <a href="index.html" class="icon icon-home"> baangt
+          
+
+          
+          </a>
+
+          
+            
+            
+          
+
+          
+<div role="search">
+  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
+    <input type="text" name="q" placeholder="Search docs" />
+    <input type="hidden" name="check_keywords" value="yes" />
+    <input type="hidden" name="area" value="default" />
+  </form>
+</div>
+
+          
+        </div>
+
+        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
+          
+            
+            
+              
+            
+            
+              <p class="caption"><span class="caption-text">Contents:</span></p>
+<ul class="current">
+<li class="toctree-l1"><a class="reference internal" href="Installation.html">   Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="OverviewUsage.html">   Overview</a></li>
+<li class="toctree-l1"><a class="reference internal" href="simpleExample.html">   First Steps</a></li>
+<li class="toctree-l1"><a class="reference internal" href="Structure.html">   Structure</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ParametersConfigFile.html">   Parameters</a></li>
+<li class="toctree-l1"><a class="reference internal" href="DataFile.html">   Data file</a></li>
+<li class="toctree-l1"><a class="reference internal" href="SimpleAPI.html">   First API Test</a></li>
+<li class="toctree-l1"><a class="reference internal" href="TestTypes.html">   Types of Tests</a></li>
+<li class="toctree-l1"><a class="reference internal" href="Developer.html">   For Developers</a></li>
+<li class="toctree-l1"><a class="reference internal" href="HistoryAndReasons.html">   History</a></li>
+<li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
+<li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
+<li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1 current"><a class="current reference internal" href="#">   Browser Drivers</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="#new-release-of-browser-drivers">New release of browser drivers</a><ul>
+<li class="toctree-l3"><a class="reference internal" href="#alternative-version">Alternative version:</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference internal" href="#older-releases-of-browser-drivers">Older releases of browser drivers</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
+<li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
+</ul>
+
+            
+          
+        </div>
+      </div>
+    </nav>
+
+    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
+
+      
+      <nav class="wy-nav-top" aria-label="top navigation">
+        
+          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
+          <a href="index.html">baangt</a>
+        
+      </nav>
+
+
+      <div class="wy-nav-content">
+        
+        <div class="rst-content">
+        
+          
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<div role="navigation" aria-label="breadcrumbs navigation">
+
+  <ul class="wy-breadcrumbs">
+    
+      <li><a href="index.html">Docs</a> &raquo;</li>
+        
+      <li>Handling of Browser Drivers</li>
+    
+    
+      <li class="wy-breadcrumbs-aside">
+        
+            
+            <a href="_sources/BrowserDrivers.rst.txt" rel="nofollow"> View page source</a>
+          
+        
+      </li>
+    
+  </ul>
+
+  
+  <hr/>
+</div>
+          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
+           <div itemprop="articleBody">
+            
+  <div class="section" id="handling-of-browser-drivers">
+<h1>Handling of Browser Drivers<a class="headerlink" href="#handling-of-browser-drivers" title="Permalink to this headline">¶</a></h1>
+<p>When you install <code class="docutils literal notranslate"><span class="pre">baangt</span></code> the latest version of Chromedriver and Geckodriver (for Firefox) are included. Depending on your
+situation you might need different drivers.</p>
+<div class="section" id="new-release-of-browser-drivers">
+<h2>New release of browser drivers<a class="headerlink" href="#new-release-of-browser-drivers" title="Permalink to this headline">¶</a></h2>
+<p>As you work with <code class="docutils literal notranslate"><span class="pre">baangt</span></code> for a longer time your browsers might be updated. If you receive an error telling about wrong
+version of browser driver, you can simply delete the existing driver in <code class="docutils literal notranslate"><span class="pre">baangt/BrowserDrivers/</span></code> and on the next start
+<code class="docutils literal notranslate"><span class="pre">baangt</span></code> will automatically download the latest version.</p>
+<div class="section" id="alternative-version">
+<h3>Alternative version:<a class="headerlink" href="#alternative-version" title="Permalink to this headline">¶</a></h3>
+<p>If you start baangt with the following syntax from the command line, it will download the latest drivers (Chrome and
+Firefox) automatically:</p>
+<p><code class="docutils literal notranslate"><span class="pre">`python3</span> <span class="pre">baangt.py</span> <span class="pre">--reloadDrivers=True`</span></code></p>
+<p>It will overwrite existing versions.</p>
+</div>
+</div>
+<div class="section" id="older-releases-of-browser-drivers">
+<h2>Older releases of browser drivers<a class="headerlink" href="#older-releases-of-browser-drivers" title="Permalink to this headline">¶</a></h2>
+<p>Please download the release that you need from chrome and/or Firefox and replace the existing files in <code class="docutils literal notranslate"><span class="pre">baangt/BrowserDrivers/</span></code>
+which the freshly downloaded, older version. After the next start it should work fine.</p>
+</div>
+</div>
+
+
+           </div>
+           
+          </div>
+          <footer>
+  
+    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
+      
+        <a href="articles/Articles.html" class="btn btn-neutral float-right" title="Not Exactly Documentation" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
+      
+      
+        <a href="PlannedFeatures.html" class="btn btn-neutral float-left" title="Future Features" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> Previous</a>
+      
+    </div>
+  
+
+  <hr/>
+
+  <div role="contentinfo">
+    <p>
+        &copy; Copyright 2020, Bernhard Buhl
+
+    </p>
+  </div>
+  Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. 
+
+</footer>
+
+        </div>
+      </div>
+
+    </section>
+
+  </div>
+  
+
+
+  <script type="text/javascript">
+      jQuery(function () {
+          SphinxRtdTheme.Navigation.enable(true);
+      });
+  </script>
+
+  
+  
+    
+   
+
+</body>
+</html>

+ 5 - 4
docs/_build/html/DataFile.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Special functions in datafiles &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>Special functions in datafiles &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -95,6 +95,7 @@
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>
@@ -165,8 +166,8 @@
 <h1>Special functions in datafiles<a class="headerlink" href="#special-functions-in-datafiles" title="Permalink to this headline">¶</a></h1>
 <p>Datafiles (or in Excel Simple format simply a tab “data”) generally hold the data for one or more testcases.</p>
 <p>The first line of the datafile holds the header line. Each cell in the header must have a unique value and acts as variablename,
-that you can use for either checking, for IF-Statements or as values to write into fields or comapare with assertions.</p>
-<p>Additionally there are some reserved names, that deliver the following functionality:</p>
+which you can use for checking, for IF-Statements or as values to write into fields or compare with assertions.</p>
+<p>Additionally there are some reserved names that deliver the following functionality:</p>
 <table class="colwidths-given docutils align-default" id="id1">
 <caption><span class="caption-text">Field names in Datafiles and their function</span><a class="headerlink" href="#id1" title="Permalink to this table">¶</a></caption>
 <colgroup>
@@ -179,7 +180,7 @@ that you can use for either checking, for IF-Statements or as values to write in
 </tr>
 </thead>
 <tbody>
-<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">TC</span> <span class="pre">Expected</span> <span class="pre">Error</span></code></p></td>
+<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">TC</span> <span class="pre">Expected</span> <span class="pre">Error</span></code> (!sic)</p></td>
 <td><p>When set to value <code class="docutils literal notranslate"><span class="pre">X</span></code>, the Test case is supposed to fail. If it fails (as expected) the status of the testcase is set to OK.</p></td>
 </tr>
 <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">JSON</span></code></p></td>

+ 11 - 1
docs/_build/html/Developer.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Developer guidelines for custom enhancements &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>Developer guidelines for custom enhancements &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -94,12 +94,14 @@
 <li class="toctree-l2"><a class="reference internal" href="#subclassing">Subclassing</a></li>
 <li class="toctree-l2"><a class="reference internal" href="#debugging">Debugging</a></li>
 <li class="toctree-l2"><a class="reference internal" href="#plugins">Plugins</a></li>
+<li class="toctree-l2"><a class="reference internal" href="#network-trace">Network trace</a></li>
 </ul>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="HistoryAndReasons.html">   History</a></li>
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>
@@ -213,6 +215,14 @@ breakpoints and expect the program to halt on the breakpoint. You’ve two chanc
 <p>Please make yourself familiar with <a class="reference external" href="https://pluggy.readthedocs.io/en/latest/">https://pluggy.readthedocs.io/en/latest/</a> in order to implement Plugins.
 If you’re stuck let me know.</p>
 </div>
+<div class="section" id="network-trace">
+<h2>Network trace<a class="headerlink" href="#network-trace" title="Permalink to this headline">¶</a></h2>
+<p>Sometimes it’s useful (especially for frontend debugging and in performance measurments) to have more detailed log about
+the calls that the browser exchanges with the backend. If you need this, use <code class="docutils literal notranslate"><span class="pre">TC.NetworkInfo</span></code> with value = <code class="docutils literal notranslate"><span class="pre">True</span></code>.
+In the output file you’ll see a new tab “Network” that shows all calls, headers, payload and timing information for each
+call.</p>
+<p>Use with care, as the file can get pretty big.</p>
+</div>
 </div>
 
 

+ 2 - 1
docs/_build/html/HistoryAndReasons.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Why baangt and why is it open source? &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>Why baangt and why is it open source? &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -99,6 +99,7 @@
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>

+ 2 - 1
docs/_build/html/Installation.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Installation &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>Installation &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -100,6 +100,7 @@
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>

+ 33 - 30
docs/_build/html/OverviewUsage.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>What is baangt &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>What is baangt &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -85,7 +85,7 @@
 <li class="toctree-l1"><a class="reference internal" href="Installation.html">   Installation</a></li>
 <li class="toctree-l1 current"><a class="current reference internal" href="#">   Overview</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="#the-fastest-simplest-way-to-record-test-cases">The fastest, simplest way to record test cases</a></li>
-<li class="toctree-l2"><a class="reference internal" href="#still-simple-and-more-powerful-ways">Still simple and more powerful ways:</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="#more-powerful-and-still-ways">More powerful and still ways:</a><ul>
 <li class="toctree-l3"><a class="reference internal" href="#hey-why-not-do-everything-in-excel">Hey, why not do everything in Excel?</a></li>
 </ul>
 </li>
@@ -105,6 +105,7 @@
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>
@@ -173,48 +174,50 @@
             
   <div class="section" id="what-is-baangt">
 <h1>What is <code class="docutils literal notranslate"><span class="pre">baangt</span></code><a class="headerlink" href="#what-is-baangt" title="Permalink to this headline">¶</a></h1>
-<p>Testing software has always been a challenging field and it’s not getting easier or simpler as overall complexity in corporate
+<p>Testing software has always been a challenging field, and it’s not getting easier or simpler, as overall complexity in corporate
 and other applications skyrockets. Release cycles in larger corporations are often long because of inefficient regression
-tests. Also costs of software updates, upgrades and forward development is heavily impacted by too little test coverage.</p>
-<p><strong>To stop praying when you release to production you need to start serious testing!</strong></p>
-<p>With <code class="docutils literal notranslate"><span class="pre">baangt</span></code> youve one <em>open source</em> solution for all your test stages and needs. Be it Frontend with Webbrowser, API,
+tests. Also costs of software updates, upgrades and forward development are heavily impacted by too little test coverage.</p>
+<p><strong>To stop praying when you release to production, you need to start serious testing!</strong></p>
+<p>With <code class="docutils literal notranslate"><span class="pre">baangt</span></code> you have one <em>open source</em> solution for all your test stages and needs. Be it Frontend with Webbrowser, API,
 graphQL, SOAP, oData or chromium related App-Tests. You’ll use one toolset, one database per stage and one reporting to
 see at any given moment, how your stages and applications are doing and if it’s safe to release the current state of one
 stage to the next.</p>
 <blockquote>
-<div><p><code class="docutils literal notranslate"><span class="pre">baangt</span></code> is optimized to be super easy to start and flexible when your demand grows.</p>
+<div><p><code class="docutils literal notranslate"><span class="pre">baangt</span></code> is optimized to be super easy to start, and flexible when your demand grows.</p>
 </div></blockquote>
 <div class="section" id="the-fastest-simplest-way-to-record-test-cases">
 <h2>The fastest, simplest way to record test cases<a class="headerlink" href="#the-fastest-simplest-way-to-record-test-cases" title="Permalink to this headline">¶</a></h2>
-<p>If your requirements are pretty basic you’d start using <code class="docutils literal notranslate"><span class="pre">baangt</span></code> with a simple Excel-Sheet as source of Testcase definition and
-Testdata definition. This is super fast, very easy even for endusers but has limited flexibility, even though it comes packed
+<p>If your requirements are pretty basic, you’d start using <code class="docutils literal notranslate"><span class="pre">baangt</span></code> with a simple Excel-Sheet as source of Testcase definition and
+Testdata definition. This is super fast, very easy even for end-users but has limited flexibility, even though it comes packed
 with all features of the higher end solutions like reporting, fault tolerance, screenshots in case of errors and much more.</p>
 </div>
-<div class="section" id="still-simple-and-more-powerful-ways">
-<h2>Still simple and more powerful ways:<a class="headerlink" href="#still-simple-and-more-powerful-ways" title="Permalink to this headline">¶</a></h2>
-<p>As your requirements grow you’d have Testcase and testrun definition separately (e.g. you want to execute the same
+<div class="section" id="more-powerful-and-still-ways">
+<h2>More powerful and still ways:<a class="headerlink" href="#more-powerful-and-still-ways" title="Permalink to this headline">¶</a></h2>
+<p>As your requirements grow you want to have Testcase and testrun definition separately (e.g. you want to execute the same
 test cases on different stages of your system landscape (Pre-Quality, Final-Quality, Dev) and not for every heartbeat test
-you’d want to run through your 1000s of test data. Maybe you’ll have a SQL-Query in your Excel based data, which changes
-data records dynamically or per stage or per version, that you want to test for. Things are not so simple in this stage,
-but still simple enough for technically versed business department to run high quality tests on all stages by themselves.
-Even after the point, where you need technicians to integrate baangt with your CD/CI-Pipeline`s buildmanagement tools,
+you would want to run through your 1000s of records of test data. Maybe you will have a SQL-Query in your Excel based data, which changes
+data records dynamically or per stage or per version, that you want to test for.</p>
+<p>Things are not so simple in this stage, but still simple enough for technically versed business department to run high
+quality tests on all stages by themselves.</p>
+<p>Even after the point, where you need technicians to integrate baangt with your CD/CI-Pipeline`s build-management tools,
 the maintenance of data and test sequence can be done without ANY other tools (except Excel or OpenOffice) easily by the
 people who know best what to test: Your business department.</p>
 <div class="section" id="hey-why-not-do-everything-in-excel">
 <h3>Hey, why not do everything in Excel?<a class="headerlink" href="#hey-why-not-do-everything-in-excel" title="Permalink to this headline">¶</a></h3>
-<p>There is one serious drawback from this flexibilty: it’s <strong>change</strong>. Of course you started with 1 sheet, but later had some additional
-requirements and simply added a second sheet to cover those whithout changing the definitions of the first excel sheet.
+<p>There is one serious drawback from this flexibility: it’s <strong>change</strong>. Of course you started with 1 sheet, but later had some additional
+requirements and simply added a second sheet to cover those without changing the definitions of the first excel sheet.
 You’re still happy as you need both behaviours tested (imagine one test set for regional customers and another test set
-for customers from other countries). Great. Everything works. After having some serious problems in production and fixing
-those defects you decide to write a testcase to mimic a certain user behaviour (e.g. navigating back and forth multiple
-times, deleting and re-adding objects from a shopping chart, etc.). The basic test sequence would be still the same as in
+for customers from other countries). Great. Everything works.</p>
+<p>After having some serious problems in production and fixing
+those defects, you decide to write a testcase to mimic a certain user behavior (e.g. navigating back and forth multiple
+times, deleting and re-adding objects from a shopping cart, etc.). The basic test sequence would still be the same as in
 the other two cases, but for a specific card you’ll need changes. Simple. You copy one of the original sheets and adjust
 accordingly. You immediately sleep better because now also those cases are part of your growing regression test set. Wonderful.
-You continue like this for 2 months, end up with 2 or 3 datafiles and 20 test case definitions. That’s not uncommon. Also
+You continue like this for 2 months, end up with 2 or 3 datafiles and 20 test case definitions. That’s not uncommon. What is also
 not uncommon is “<strong>Change</strong>”. For more direct communication with the endusers the AUT (Application under test) get’s enriched
 with a Sentry-Popup. Wonderful idea. But wait… It’s not so great after all, because now you have to update 20 test case
-definitions with a way to deal with the new popup. Imagine corporate environments where we have many 1.000 or many 10.000
-tests.</p>
+definitions with a way to deal with the new popup. Imagine corporate environments where we have many thousands or many tens of
+thousands tests.</p>
 </div>
 </div>
 <div class="section" id="subclassing-for-multiply-used-functionality">
@@ -237,7 +240,7 @@ for your TestCase.</p>
 <p>You can subclass any other functionality, that doesn’t fully fit your needs (IBAN-Generation, Browser-Handling, Timing)
 and also create your own Assertion-classes (for instance if you need to receive data from a Host-System or
 RFC/SOAP-Connection or any other source that is not natively supported by <code class="docutils literal notranslate"><span class="pre">baangt.py</span></code>). Of course you’d only
-re-implement methods, that you need to enrich and consume everything else from the framework.</p>
+re-implement methods that you need to enrich, and consume everything else from the framework.</p>
 <p>Please consider creating pull-requests if you think some of your custom implemented functionality could be useful for
 others.</p>
 </div>
@@ -246,12 +249,12 @@ others.</p>
 <p>Enter the next stage: <code class="docutils literal notranslate"><span class="pre">baangtDB</span></code>. <code class="docutils literal notranslate"><span class="pre">baangtDB</span></code> does much more than just replace Excel as input and sequence source. BaangtDB
 provides modularization of your test cases. In the above example you’d maintain the Sentry-Popup exactly ONCE for all your
 test cases, where it applies.</p>
-<p>Also if you’re in a really large corporate environment, you’ll start facing problems with the XLS-Based solution as corporate
-governance, compliance, regulations and so on will sooner or later make it difficult to use the software in this way. Also
-even if you use <code class="docutils literal notranslate"><span class="pre">git</span></code> you experience problems with different versions of the Excel-Sheets - depending on your setup of course.</p>
+<p>If you’re in a really large corporate environment, you’ll start facing problems with the XLS-Based solution, as corporate
+governance, compliance, regulations and so on will sooner or later make it difficult to use the software in this way.
+Even if you use <code class="docutils literal notranslate"><span class="pre">git</span></code> you experience problems with different versions of the Excel-Sheets - depending on your setup of course.</p>
 <p>But still no need invest into expensive, licensed, closed source, proprietary solutions and depend on their good will.
-Run <code class="docutils literal notranslate"><span class="pre">baangtDB</span></code> (for testdata and testcase sequences) in a docker container on premises or in Cloud and have the full flexibility plus
-comfort for free.</p>
+Run <code class="docutils literal notranslate"><span class="pre">baangtDB</span></code> (for testdata and testcase sequences) in a docker container, on premises or in the cloud and have the full
+flexibility plus comfort for free.</p>
 </div>
 <div class="section" id="to-sum-it-up">
 <h2>To sum it up<a class="headerlink" href="#to-sum-it-up" title="Permalink to this headline">¶</a></h2>

+ 13 - 9
docs/_build/html/ParametersConfigFile.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Parameters in Configuration files (globals) &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>Parameters in Configuration files (globals) &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -95,6 +95,7 @@
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>
@@ -163,7 +164,7 @@
             
   <div class="section" id="parameters-in-configuration-files-globals">
 <h1>Parameters in Configuration files (<code class="docutils literal notranslate"><span class="pre">globals</span></code>)<a class="headerlink" href="#parameters-in-configuration-files-globals" title="Permalink to this headline">¶</a></h1>
-<p>Generally it’s not needed to change parameters in the config files during manual or automated execution as the parameters
+<p>Generally it’s not needed to change parameters in the config files during manual or automated execution, as the parameters
 have default values or are anyway defined in the Testrun definition. Still sometimes it’s very handy to change them on the fly,
 for instance to slowly retest a single testrecord or to not close the browser after an error.</p>
 <table class="colwidths-given docutils align-default" id="id1">
@@ -179,11 +180,11 @@ for instance to slowly retest a single testrecord or to not close the browser af
 </thead>
 <tbody>
 <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">Release</span></code></p></td>
-<td><p>As you move your maturing software through the system landscape you might still need regression test results based
+<td><p>As you move your maturing software through the system landscape, you might still need regression test results based
 on “old” release functionality, while on lower stages you might want to (regression)-test already newer versions
 or newer functionality. In <code class="docutils literal notranslate"><span class="pre">baangt</span></code> there is no need to copy test cases in those situations. You simply update
-your test case definition with the apropriate version number (e.g. &gt;= 2020-10) and set the proper <code class="docutils literal notranslate"><span class="pre">Release</span></code> in
-the config file, for instance “2020-09” when you want to run on final quality and the changes from verison “2020-10”
+your test case definition with the appropriate version number (e.g. &gt;= 2020-10) and set the proper <code class="docutils literal notranslate"><span class="pre">Release</span></code> in
+the config file. For instance “2020-09” when you want to run on final quality and the changes from version “2020-10”
 are not there yet.</p>
 <blockquote>
 <div><p>Note for developers:</p>
@@ -193,12 +194,12 @@ simply subclass TestStepMaster and overwrite only the method <code class="docuti
 </td>
 </tr>
 <tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">TC.slowExecution</span></code></p></td>
-<td><p>When set to <code class="docutils literal notranslate"><span class="pre">true</span></code> the browser will stop for a short time after each command, so that you can also visually see what the browser is doing</p></td>
+<td><p>When set to <code class="docutils literal notranslate"><span class="pre">true</span></code>, the browser will stop for a short time after each command, so that you can also visually see what the browser is doing</p></td>
 </tr>
 <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">dontCloseBrowser</span></code></p></td>
-<td><p>When the browser or script finds an error usually it takes a screenshot and moves on to the next testcase. With this setting to <code class="docutils literal notranslate"><span class="pre">True</span></code> the Browsersession will stop right at the error</p></td>
+<td><p>When the browser or script finds an error, it usually takes a screenshot and moves on to the next testcase. With this setting to <code class="docutils literal notranslate"><span class="pre">True</span></code> the browser session will stop right at the error.</p></td>
 </tr>
-<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">TC.BrowserOptions</span></code></p></td>
+<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">TC.BrowserAttributes</span></code></p></td>
 <td><p>Set the value to <code class="docutils literal notranslate"><span class="pre">{'HEADLESS':</span> <span class="pre">'True'}</span></code> to run Chrome/Firefox in headless mode.</p></td>
 </tr>
 <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">TC.Lines</span></code></p></td>
@@ -214,7 +215,10 @@ simply subclass TestStepMaster and overwrite only the method <code class="docuti
 <td><p>If the testcase is WEB-Testing, then you can overwrite the browser, which is defined inside the testrun definition. If the testcase is not a Web-Testcase this setting doesn’t have any effect. Valid values are <code class="docutils literal notranslate"><span class="pre">Chrome</span></code>, <code class="docutils literal notranslate"><span class="pre">FF</span></code> and <code class="docutils literal notranslate"><span class="pre">Safari</span></code></p></td>
 </tr>
 <tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">TC.ParallelRuns</span></code></p></td>
-<td><p>Number of parallel sessions to be executing. Values depend largely on your hardware and internet connection. Debugging works only in a single session.</p></td>
+<td><p>Number of parallel sessions to be executed. Values depend largely on your hardware and internet connection. Debugging works only in a single session.</p></td>
+</tr>
+<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">TC.NetworkInfo</span></code></p></td>
+<td><p>Creates a very detailed trace of network activity of the browser(s). In the output file you’ll find another Tab “Network”, that holds all API-Calls from the frontend (including header, payload and answer).</p></td>
 </tr>
 </tbody>
 </table>

+ 17 - 11
docs/_build/html/PlannedFeatures.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Future Features &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>Future Features &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -35,7 +35,7 @@
   <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <link rel="index" title="Index" href="genindex.html" />
     <link rel="search" title="Search" href="search.html" />
-    <link rel="next" title="Not Exactly Documentation" href="articles/Articles.html" />
+    <link rel="next" title="Handling of Browser Drivers" href="BrowserDrivers.html" />
     <link rel="prev" title="Change log" href="changelog.html" /> 
 </head>
 
@@ -100,6 +100,7 @@
 <li class="toctree-l2"><a class="reference internal" href="#pro-features">PRO-Features</a></li>
 </ul>
 </li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>
@@ -172,20 +173,22 @@
 <div class="section" id="short-medium-term-features">
 <h2>Short/Medium term features<a class="headerlink" href="#short-medium-term-features" title="Permalink to this headline">¶</a></h2>
 <ul class="simple">
-<li><p>Refactoring of Multiprocessing (2020.02)</p></li>
-<li><p>Executables on Mac, Linux and Windows (2020.03)</p></li>
+<li><p>Refactoring of parallel processing on a single computer (2020.03) –&gt; Done</p></li>
+<li><p>Executables on Mac, Linux and Windows (2020.03) –&gt; Done</p></li>
 <li><dl class="simple">
 <dt>Nicer interactive UI-Starter (2020.03)</dt><dd><ul>
 <li><p>Phase 1 done 2020.02</p></li>
-<li><p>Provide live statistics (2020.03)</p></li>
+<li><p>Phase 2 (UI-elements) (2020.03) –&gt; will move to 2020.04 RC5</p></li>
+<li><p>Provide live statistics (2020.04)</p></li>
 </ul>
 </dd>
 </dl>
 </li>
-<li><p>Build-In Proxy-Server for Network traffic and timing logs (2020.03) (most probably not possible in Windows and MAC but should work in Linux)</p></li>
-<li><p>Double Opt-In Automation (2020.03)</p></li>
-<li><p>Support for Selenium Grid V4 (2020.03)</p></li>
+<li><p>Double Opt-In Automation (2020.03) –&gt; will move to 2020.04 RC6</p></li>
+<li><p>Support for Selenium Grid V4 (2020.04)</p></li>
 <li><p>Better support for multiple sources (e.g. multiple XLSX) of test data (2020.04)</p></li>
+<li><p>Better support to store test data output to database and export files (2020.04)</p></li>
+<li><p>Support for Appium integration (2020.04)</p></li>
 <li><p>Katalon Importer/Converter as Webservice (2020.04)</p></li>
 </ul>
 </div>
@@ -198,7 +201,8 @@
 <li><p>Integration with Atlassian Confluence (for Testcase and Testrun definitions)</p></li>
 <li><p>Integration with Atlassian Confluence (to publish results of testruns)</p></li>
 <li><p>Integration with MS Teams to publish results of Testruns</p></li>
-<li><p>Grafana Board for Flask-Version</p></li>
+<li><p>Integration with Telegram to publish results of Testruns</p></li>
+<li><p>Grafana Board for baangtDB</p></li>
 <li><p>Better support for oData V4.0 (similar to SOAP)</p></li>
 <li><p>Support for GraphQL via Graphene</p></li>
 </ul>
@@ -209,10 +213,12 @@
 Future features might include:</p>
 <ul class="simple">
 <li><p>DB-Migration tools (to ease the pain of upgrading databases)</p></li>
-<li><p>Multi-User environment (who did when which activity and who changed when which testobject)</p></li>
+<li><p>Multi-User environment (who did when which activity and who changed when which test object)</p></li>
 <li><p>History of Testcases (what was changed when. If urgently needed we could come up with DB-Dump and GIT diff or so.)</p></li>
 <li><p>Test-Canons (deliberately stop test cases multiple times at certain test steps, wait for trigger, then resume. After first Testcase <em>finished</em> his first waiting period, start second round of Testcases (that’s how the name “Canon” came up). So far implemented in customer project, but needs to be polished up for public version)</p></li>
 <li><p>XML/PDF-Compare</p></li>
+<li><p>Consulting</p></li>
+<li><p>Priority support</p></li>
 </ul>
 </div>
 </div>
@@ -225,7 +231,7 @@ Future features might include:</p>
   
     <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
       
-        <a href="articles/Articles.html" class="btn btn-neutral float-right" title="Not Exactly Documentation" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
+        <a href="BrowserDrivers.html" class="btn btn-neutral float-right" title="Handling of Browser Drivers" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
       
       
         <a href="changelog.html" class="btn btn-neutral float-left" title="Change log" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> Previous</a>

+ 32 - 1
docs/_build/html/SimpleAPI.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>How to create a simple API Test &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>How to create a simple API Test &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -103,6 +103,7 @@
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>
@@ -240,6 +241,36 @@ your only chance to get fields added into the result sheet.
 <code class="docutils literal notranslate"><span class="pre">value2</span></code> is the source (e.g. <code class="docutils literal notranslate"><span class="pre">$(ANSWER_CONTENT.imdbRating)</span></code> would retrieve the value “imdbRating” of the
 answer of your API-Call.</p></td>
 </tr>
+<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">ASSERT</span></code></p></td>
+<td><p>This  will retrieve value of element specified by <cite>locator</cite>
+And compare with expected_value specified in <cite>value</cite></p>
+<p>if expected_value not matches with output_value it will raise TestStepExecution and result in FAILED.</p>
+</td>
+</tr>
+<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ADDRESS_CREATE</span></code></p></td>
+<td><p>Create  Address Data for various test cases  and save in testDataDict
+The following field variable can be used via $(field_name).</p>
+<p>[‘HouseNumber’, ‘AdditionalData1’, ‘AdditionalData2’, ‘StreetName’, ‘CityName’, ‘PostalCode’, ‘CountryCode’]</p>
+<dl class="simple">
+<dt>Example:</dt><dd><p>Default Data: (value=&lt;blank&gt; and value2=&lt;blank&gt;)
+‘HouseNumber’: ‘6’, ‘AdditionalData1’: ‘Near MahavirChowk’, ‘AdditionalData2’: ‘Opposite St. Marish Church’, ‘StreetName’: ‘GoreGaon’, ‘CityName’: ‘Ambala’, ‘PostalCode’: ‘160055’, ‘CountryCode’: ‘India’</p>
+</dd>
+<dt><cite>value</cite> optional</dt><dd><dl class="simple">
+<dt>if provided<span class="classifier">(value= {“CountryCode”:”US”,”CityName”:”Athens”} value2=&lt;blank&gt;)</span></dt><dd><p>FieldValue updated to:
+{‘HouseNumber’: ‘6’, ‘AdditionalData1’: ‘Near MahavirChowk’,
+‘AdditionalData2’: ‘Opposite St. Marish Church’,
+‘StreetName’: ‘GoreGaon’, ‘CityName’: ‘Athens’,
+‘PostalCode’: ‘160055’, ‘CountryCode’: ‘US’}</p>
+</dd>
+</dl>
+</dd>
+</dl>
+<p><cite>value2</cite> optional</p>
+<blockquote>
+<div><p>Field will be prefixed with “office_&lt;field_name&gt;”. Ex. “office_CountryCode”</p>
+</div></blockquote>
+</td>
+</tr>
 </tbody>
 </table>
 </div>

+ 5 - 4
docs/_build/html/Structure.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Structure of baangt &mdash; baangt 2020.1.1.b11 documentation</title>
+  <title>Structure of baangt &mdash; baangt 2020.3.0.rc4 documentation</title>
   
 
   
@@ -102,6 +102,7 @@
 <li class="toctree-l1"><a class="reference internal" href="contributors.html">   Contributions</a></li>
 <li class="toctree-l1"><a class="reference internal" href="changelog.html">   Changelog</a></li>
 <li class="toctree-l1"><a class="reference internal" href="PlannedFeatures.html">   Planned Features</a></li>
+<li class="toctree-l1"><a class="reference internal" href="BrowserDrivers.html">   Browser Drivers</a></li>
 <li class="toctree-l1"><a class="reference internal" href="articles/Articles.html">:subheader: Articles</a></li>
 <li class="toctree-l1"><a class="reference external" href="http://www.baangt.org">   Web</a></li>
 </ul>
@@ -170,7 +171,7 @@
             
   <div class="section" id="structure-of-baangt">
 <h1>Structure of baangt<a class="headerlink" href="#structure-of-baangt" title="Permalink to this headline">¶</a></h1>
-<p>If you never used any test automation software before these terms can be intimidating, but in reality it’s all very simple.</p>
+<p>If you never used any test automation software before, these terms can be intimidating, but in reality it’s all very simple.</p>
 <p>We’ll start from the bottom to the top.</p>
 <div class="section" id="teststep">
 <h2>TestStep<a class="headerlink" href="#teststep" title="Permalink to this headline">¶</a></h2>
@@ -191,7 +192,7 @@ Duration in Seconds)</p>
 <p>A Testcase is a Sequence of TestStepSequences. You might wonder, why this additional TestStepSequence is needed, why not
 simply write the TestSteps directly into the TestCase.</p>
 <p>First of all: you don’t need the TestStepSequence. In the simple XLSX-Format this grouping area doesn’t exist.
-Second: Imagine youve a login-page, a product bucket, product return functionality and invoice reprint functionality in
+Second: Imagine you have a login-page, a product bucket, product return functionality and invoice reprint functionality in
 your SPA and you want to test all of them. Obviously you’ll have at least 3 Testcases, but in all of them you’ll have to
 do a login. You can use the TestStepSequence to extract this repeated Sequence.</p>
 <p>In a Testcase we define not only the Sequence of TestStepSequences but also which type of Testcase (Browser, API, etc.)
@@ -207,7 +208,7 @@ connection to the datafile(s) to be used and which records to process in this Te
 for instance group together the execution of a WEB-Page TestCase and subsequently the execution of an API-Call to retrieve
 results from another system. This scenario is of course mostly for corporate system landscapes, where the frontend (Web) communicates
 more or less asynchronous with backend components like Hosts, CRM-Systems, SAP-Backends and so on.</p>
-<p>By all means - if you don’t need it - don’t use it. But in case you need it, it’s good to know it’s there.</p>
+<p>By all means if you don’t need it: don’t use it. But in case you need it, it’s good to know it’s there.</p>
 </div>
 <div class="section" id="testrun">
 <h2>TestRun<a class="headerlink" href="#testrun" title="Permalink to this headline">¶</a></h2>

+ 0 - 0
docs/_build/html/TestTypes.html


Some files were not shown because too many files changed in this diff