def __dictToActionBundle(self) -> ActionBundle: dataDict = self._source # We don't want to stall the app in case of missing/wrong directories/files. # So we just return an empty ActionBundle if for some reason there is no JSON data: if dataDict is None or not dataDict.get("actions") or len( dataDict.get("actions")) == 0: return ActionBundle.createNew() # Convert action: Action actions: [Action] = [] try: for actionDict in dataDict.get("actions"): action = DictActionConverter(source=actionDict, target=Action).getConverted() if isinstance(action, Action): actions.append(action) actionBundle = ActionBundle(name=dataDict['name'], actions=actions) return actionBundle except KeyError: logger.warning("Key of actionDict could not be mapped.", exc_info=True) return ActionBundle.createNew() except Exception as e: logger.error("Unexpected exception. %s", e, exc_info=True) raise
def test_run_shouldRaiseOnException(self): # Given action = Mock(spec=['execute', 'command']) action.command.readable.return_value = "Mocked action command" action.execute.side_effect = Exception("This is a mocked exception.") sut = ActionBundle(name="A failing Actionbundle", actions=[action]) # When / Then with self.assertRaises(Exception): sut.run(browser=self.__nullBrowser)
def test_run_withZeroActionsShouldDoNothing(self): # Given action1 = Mock(spec=[Action, 'execute']) sut = ActionBundle(name="Actionbundle without actions", actions=[]) # When sut.run(browser=self.__nullBrowser) # Then action1.execute.assert_not_called()
def test_run_withNoneActionsShouldDoNothing(self): # Given action1 = Mock(spec=[Action, 'execute']) # noinspection PyTypeChecker sut = ActionBundle(name="Actionbundle without actions", actions=None) # When sut.run(browser=self.__nullBrowser) # Then action1.execute.assert_not_called()
def test_run_shouldCallProxyInsteadOfDirectCall(self): # Given action1 = Mock(spec=[Action, 'execute']) sut = ActionBundle(name="A test Actionbundle name", actions=[action1]) with mock.patch('story.actionBundle.ActionProxy', autospec=True) as proxy: # When sut.run(browser=self.__nullBrowser) # Then proxy(action1).execute.assert_called_once() action1.execute.assert_not_called()
def test_run_withValidDataShouldLoopOverActions(self): # Given action1 = Mock(spec=[Action, 'execute']) action2 = Mock(spec=[Action, 'execute']) action3 = Mock(spec=[Action, 'execute']) sut = ActionBundle(name="A test Actionbundle name", actions=[action1, action2, action3]) # When sut.run(browser=self.__nullBrowser) # Then action1.execute.assert_called_once() action2.execute.assert_called_once() action3.execute.assert_called_once()
def test_save_shouldPersistGivenActionBundleAsJSON(self): # Note that we are testing only basic expectations here. Conversion from # ActionBundle to JSON/dict object is tested with dedicated methods # within the converter test classes. # Given searchConditions = SearchConditions(strategy=Strategy.BY_XPATH, identifier="Nothing") action1 = LoadPageAction(url="https://test.url.de") action2 = SendKeysAction(searchConditions=searchConditions, text="Some test to send") actionBundle = ActionBundle(name="Saving test - Test story", actions=[action1, action2]) path = self.ACTIONBUNDLE_TEST_DIR_PATH / f"{actionBundle.name}.json" sut = JSONActionBundleDao(str(path)) # Precondition: Test directory for JSON files must be present assert path.parent.is_dir() # When sut.connection.open() sut.saveAll(data=actionBundle) # Then # Expect the file was created. self.assertTrue(path.is_file(), f"Expected file at path {path} but there is no file at this path.") # Expect that there is some content in the file which has the title # of the ActionBundle in it. sut.connection.db.seek(0) rawTextFromSavedFile = sut.connection.db.readline(300) sut.connection.db.close() self.assertIn(actionBundle.name, rawTextFromSavedFile) # Cleanup, remove test file. if path.is_file(): path.unlink()
def test_init_shouldRaiseIfOneOrBothArgumentsAreOfNoneType(self): # Given source = None target = {"that": "this"} # When / Then with self.assertRaises(ValueError): BaseConverter(source=source, target=target, allowedTypes=(ActionBundle, dict)) # Given source = ActionBundle(name="What", actions=[]) target = None # When / Then with self.assertRaises(ValueError): BaseConverter(source=source, target=target, allowedTypes=(ActionBundle, dict)) # Given source = None target = None # When / Then with self.assertRaises(ValueError): BaseConverter(source=source, target=target, allowedTypes=(ActionBundle, dict))
def __init__(self, *args, **kwargs): logger.debug("Initializing class %s", __class__.__name__) # Order of steps is important from here. # 1. Load UI file super(MainWindowController, self).__init__(*args, **kwargs) uic.loadUi("mainWindow.ui", self) # Loads all widgets of .ui into my instance # 2. Init priority properties # Set StoryLogHandler which is responsible for logging into a GUI-Widget self.storyLogHandler = StoryLogHandler() # Thread handling. We later need to access the worker while running, # to be able to force stop it. So preserve window lifecycle. self.storyWorker = None # Keep thread lifecycle, so we don't need to create any new as long as this window lives self.workerThread = QThread() # Bind GUI elements. self.defineConnections() # 3. Init general properties which may depend on step 2. self.storyData = ActionBundle.createNew() # 4. Init UI self.initView()
def test_name_shouldReturnValidValue(self): # Given expectedName = "This is a test name" # When sut = ActionBundle(name=expectedName, actions=[]) # Then self.assertEqual(expectedName, sut.name)
def test_run_shouldStopLoopWhenReceivedStopSignal(self): # Given action1 = Mock(spec=[Action, 'execute']) action2 = Mock(spec=[Action, 'execute']) sut = ActionBundle(name="A callback Actionbundle", actions=[action1, action2]) def stopImmediately(): sut.stop() # When sut.run(browser=self.__nullBrowser, callback=lambda _: stopImmediately()) # Then # Two actions were configuration in this test but we called stop after the # first callback and expect the 2nd action not to be called at all. action2.execute.assert_not_called()
def test_run_shouldCallbackIfCallbackMethodIsGiven(self): # Given action1 = Mock(spec=[Action, 'execute']) action2 = Mock(spec=[Action, 'execute']) myCallback = Mock(spec=["action"]) expectedCallbackArgs = [mock.call(action1), mock.call(action2)] sut = ActionBundle(name="A callback Actionbundle", actions=[action1, action2]) # When sut.run(browser=self.__nullBrowser, callback=lambda action: myCallback(action)) # Then # Two actions were configured in this test, so we expect 2 callbacks self.assertEqual(2, myCallback.call_count) # Expect that configured test-actions get passed back along with the callback self.assertEqual(expectedCallbackArgs, myCallback.call_args_list)
def test_getConverted_toDict_shouldReturnValidDict(self): # Given sc1 = Mock(spec_set=SearchConditions) sc2 = Mock(spec_set=SearchConditions) sc1.searchStrategy.value = "strategy1" sc1.identifier = "id1" sc2.searchStrategy.value = "strategy2" sc2.identifier = "id2" action1 = SubmitAction(searchConditions=sc1) action2 = SendKeysAction(searchConditions=sc2, text="This is a test text to send") actionBundle = ActionBundle(name="A test title", actions=[action1, action2]) converter = self.sut(source=actionBundle, target=dict, table=self.TABLE_NAME) # When dataDict = converter.getConverted() # Then # Expect it is a dict object self.assertIsInstance(dataDict, dict) # Expect the dict has 3 items self.assertEqual(3, len(dataDict)) # Expect it has a "name" key on its top level self.assertIn("name", dataDict) # Expect it has an "version" key on its top level self.assertIn("version", dataDict) # Expect it has an "actions" key on its top level self.assertIn("actions", dataDict) # Expect the dict has a list of 2 actions self.assertEqual(2, len(dataDict["actions"])) # Expect the 1st item of array "actions" has a key "command" self.assertIn("command", dataDict["actions"][0]) # Expect the command value for key "command" matches 5 (which is ActionCmd.SUBMIT) self.assertEqual(5, dataDict["actions"][0]["command"]) # Expect value of key "searchStrategy" and "searchIdentifier" # in the 1st item of array "actions" to match the formerly given values self.assertIn("searchStrategy", dataDict["actions"][0]) self.assertEqual("strategy1", dataDict["actions"][0]["searchStrategy"]) self.assertIn("searchIdentifier", dataDict["actions"][0]) self.assertEqual("id1", dataDict["actions"][0]["searchIdentifier"]) # Expect the 2nd item of array "actions" has a key "textToSend" self.assertIn("textToSend", dataDict["actions"][1]) # Expect the value for key "textToSend" matches self.assertEqual("This is a test text to send", dataDict["actions"][1]["textToSend"]) # Expect value of key "searchStrategy" and "searchIdentifier" # in the 2nd item of array "actions" to match the formerly given values self.assertIn("searchStrategy", dataDict["actions"][1]) self.assertEqual("strategy2", dataDict["actions"][1]["searchStrategy"]) self.assertIn("searchIdentifier", dataDict["actions"][1]) self.assertEqual("id2", dataDict["actions"][1]["searchIdentifier"])
def test_createNew_shouldCreateValidActionBundle(self): # Given expectedName = "New" # When sut = ActionBundle.createNew() # Then self.assertEqual(expectedName, sut.name) self.assertEqual(0, len(sut.actions))
def test_actionBundle_shouldReturnValidActions(self): # Given action1 = Mock(spec=Action) action1.name = "mock 1 name" action2 = Mock() action2.name = "mock 2 name" # When sut = ActionBundle(name="some", actions=[action1, action2]) # Then self.assertEqual("mock 1 name", sut.actions[0].name) self.assertEqual("mock 2 name", sut.actions[1].name)
def test__init_shouldSetSourceAndTargetPropertiesIfArgumentsAreValid(self): # Given source: ActionBundle = ActionBundle(name="A test name", actions=[]) target: type = dict # When sut = BaseConverter(source=source, target=target, allowedTypes=(ActionBundle, dict)) # Then self.assertIsInstance(sut._source, ActionBundle) self.assertEqual("A test name", sut._source.name) self.assertIsInstance(sut._target, type)
def test_getConverted_toDict_shouldReturnValidDictIfActionBundleHasNoActions( self): # Given actionBundle = ActionBundle(name="Test title", actions=[]) converter = self.sut(source=actionBundle, target=dict, table=self.TABLE_NAME) # When dataDict = converter.getConverted() # Then # Expect it is a dict object self.assertIsInstance(dataDict, dict) # Expect we have a dict with 3 items self.assertEqual(3, len(dataDict)) self.assertIn("name", dataDict) self.assertEqual("Test title", dataDict["name"]) self.assertIn("actions", dataDict) self.assertEqual(0, len(dataDict["actions"]))
def test_insert(self): # Given stubFile = JSONActionBundleDaoFixture.Filename.GOOGLE_SEARCH.value stubPath = Path(self.ACTIONBUNDLE_TEST_DIR_PATH / stubFile) testPath = Path( self.ACTIONBUNDLE_TEST_DIR_PATH / f"{__class__.__name__}.test_insert.json") # Copy a test JSON file with fixed data shutil.copy(stubPath, testPath) assert testPath.exists() # Create some test data to insert searchConditions = SearchConditions(strategy=Strategy.BY_XPATH, identifier="Nothing") action01 = LoadPageAction(url="https://some.url.com") action02 = SendKeysAction( searchConditions=searchConditions, text="Some test text here." ) actions = [action01, action02] actionBundle = ActionBundle(name="A new inserted ActionBundle", actions=actions) # Data expressed as expected dict expectedDict = { "version": 1.0, "name": "A new inserted ActionBundle", "actions": [ { "command": 2, "searchStrategy": "", "searchIdentifier": "", "textToSend": "https://some.url.com", "maxWait": 0.0 }, { "command": 3, "searchStrategy": "xPath", "searchIdentifier": "Nothing", "textToSend": "Some test text here.", "maxWait": 0.0 } ] } # When with JSONActionBundleDao(str(testPath)) as sut: sut.insert(actionBundle) # Then with open(str(testPath), "r", encoding="utf-8") as file: savedData = json.load(file) actionBundleTable = savedData.get(JSONActionBundleDao._TABLE_NAME) # Expect that there is a root node with key JSONActionBundleDao._TABLE_NAME self.assertIsNotNone(actionBundleTable, f"Expected data for table {JSONActionBundleDao._TABLE_NAME}, " f"got None. Table does not seem to exist in data: {savedData}") # Expect that actionBundleTable is of type list and has 2 entries self.assertIsInstance(actionBundleTable, list) self.assertEqual(2, len(actionBundleTable)) # Expect correct values for inserted data insertedData = actionBundleTable[1] self.assertDictEqual(expectedDict, insertedData) # Cleanup if testPath.is_file(): testPath.unlink()