Repository: robotframework/SeleniumLibrary (python)

Issue:
Plugins should be last thing loaded in the SeleniumLibrary __init__
In the library init, plugins are loaded after the Event Firing WebDriver. There was discussion in the slack that user wants to plugin to also add a Event Firing WebDriver class to the library. But this is not currently possible because plugins are loaded before the Event Firing WebDriver and it overwrites what plugin is doing.

To overcome this problem, add plugins as last in the SeleniumLibrary [__init__](https://github.com/robotframework/SeleniumLibrary/blob/master/src/SeleniumLibrary/__init__.py#L348). 

Pull request:
Fixed initialisation order
Fixes #1424

Patch:
diff --git a/docs/extending/extending.rst b/docs/extending/extending.rst
index 9960ab02..d143e884 100644
--- a/docs/extending/extending.rst
+++ b/docs/extending/extending.rst
@@ -89,6 +89,15 @@ of the attributes are explained in the library `keyword documentation`_. please
 plugins may alter the functionality of the method or attributes and documentation applies
 only for the core SeleniumLibrary.
 
+Initialisation order
+====================
+When instance is created from the SeleniumLibrary, example when library is imported in the
+test data, there is an order in the initialisation. At first all classes defining SeleniumLibrary
+keywords are discovered. As a second event, discovery for the EventFiringWebDriver is done.
+At third event, plugins are discovered. As a last event, keywords are found from SeleniumLibrary
+classes and plugins. Because plugins are discovered last, they may example alter the
+EventFiringWebDriver. Consult the plugin's documentation for more details.
+
 Plugins
 =======
 SeleniumLibrary offers plugins as a way to modify, add library keywords and modify some of the internal
diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py
index 0a53d434..59bde1ca 100644
--- a/src/SeleniumLibrary/__init__.py
+++ b/src/SeleniumLibrary/__init__.py
@@ -460,17 +460,16 @@ class SeleniumLibrary(DynamicCore):
             WaitingKeywords(self),
             WindowKeywords(self)
         ]
+        self.ROBOT_LIBRARY_LISTENER = LibraryListener()
+        self._running_keyword = None
+        self.event_firing_webdriver = None
+        if is_truthy(event_firing_webdriver):
+            self.event_firing_webdriver = self._parse_listener(event_firing_webdriver)
         if is_truthy(plugins):
             plugin_libs = self._parse_plugins(plugins)
             libraries = libraries + plugin_libs
         self._drivers = WebDriverCache()
         DynamicCore.__init__(self, libraries)
-        self.ROBOT_LIBRARY_LISTENER = LibraryListener()
-        if is_truthy(event_firing_webdriver):
-            self.event_firing_webdriver = self._parse_listener(event_firing_webdriver)
-        else:
-            self.event_firing_webdriver = None
-        self._running_keyword = None
 
     def run_keyword(self, name, args, kwargs):
         self._running_keyword = name


Test patch:
diff --git a/utest/test/api/plugin_tester.py b/utest/test/api/plugin_tester.py
new file mode 100644
index 00000000..af90e679
--- /dev/null
+++ b/utest/test/api/plugin_tester.py
@@ -0,0 +1,16 @@
+from SeleniumLibrary.base import LibraryComponent, keyword
+
+
+class plugin_tester(LibraryComponent):
+
+    def __init__(self, ctx):
+        LibraryComponent.__init__(self, ctx)
+        ctx.event_firing_webdriver = 'should be last'
+
+    @keyword
+    def foo(self):
+        self.info('foo')
+
+    @keyword
+    def bar(self, arg):
+        self.info(arg)
diff --git a/utest/test/api/test_plugins.py b/utest/test/api/test_plugins.py
index b594866c..d84a8d16 100644
--- a/utest/test/api/test_plugins.py
+++ b/utest/test/api/test_plugins.py
@@ -103,3 +103,9 @@ class ExtendingSeleniumLibrary(unittest.TestCase):
         no_inherit = os.path.join(self.root_dir, 'my_lib_not_inherit.py')
         with self.assertRaises(PluginError):
             SeleniumLibrary(plugins=no_inherit)
+
+    def test_plugin_as_last_in_init(self):
+        plugin_file = os.path.join(self.root_dir, 'plugin_tester.py')
+        event_firing_wd = os.path.join(self.root_dir, 'MyListener.py')
+        sl = SeleniumLibrary(plugins=plugin_file, event_firing_webdriver=event_firing_wd)
+        self.assertEqual(sl.event_firing_webdriver, 'should be last')