示例#1
0
    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()
示例#8
0
    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)
示例#16
0
    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()