Reloading a Chrome Extension using Selenium WebDriver
How to reload Chrome Extensions in Selenium WebDriver if they don’t work on first try!
Some automated tests require browser extensions to complete an action. For instance, testing whether a login ‘Remember Me’ works via a cookie.
However, not all browser extensions work immediately. Some of Chrome’s must be refreshed first, for it to work as expected.
This tutorial will show you a script that will refresh a Chrome extension before a test begins.
The Scenario
We want to log in to a sample site with a cookie. To store this cookie, I will use the Chrome ModHeader extension in this tutorial. First, start Chrome with the extension (I used this tutorial for how to drive Chrome with Extensions using Selenium WebDriver).
Following this, just running the basic test will give you this window:
It knows we are trying to open ModHeader (in the top bar), but cannot access it.
If we manually go to the Extension Manager (chrome://extensions
), there is a reload option for each extension (highlighted in red below).
Click it to see a “Reloaded” toast. Now if we return to ModHeader again, it will have loaded properly.
These are the basic steps we want our script to be able to replicate.
In summary, to load an extension properly we want to write a script that will:
- Navigate to the Extension Manager
- Reload Affected Extension
- Return to the Extension’s Page
Navigate to the Extension Manager
This step should be familiar! Just navigate to the extensions page.
driver.get(“chrome://extensions”)
Reload Affected Extension
Here is the tricky part, we just want to click the ‘reload’ button. However, Chrome’s extension manager makes use of nested shadow roots (see my previous tutorial on automating Shadow DOM with Selenium WebDriver).
In the above screenshot, the reload button is actually under three shadow roots!
Some keen readers may notice that there is another shadow root under the<cr-view-manager>
tag. Good spotting, but the reload button is not nested under it so we can ignore it for this tutorial.
Like the previous tutorial, we will execute JavaScript to isolate the shadow roots; but this time do it three times over.
# first shadow root, call from driver
elem1 = driver.find_element(:tag_name, "extensions-manager")
shadow_root1 = driver.execute_script("return arguments[0].shadowRoot", elem1)# second shadow_root, call from shadow_root1
elem2 = shadow_root1.find_element(:tag_name, "extensions-item-list")
shadow_root2 = driver.execute_script("return arguments[0].shadowRoot", elem2)# third shadow_root, call from shadow_root2
elem3 = shadow_root2.find_element(:tag_name, "extensions-item")
shadow_root3 = driver.execute_script("return arguments[0].shadowRoot", elem3)
It is important to note that we get our inner shadow root from it’s direct shadow root parent (or driver if it is the outermost).
Finally, within our focused shadow root, shadow_root3
, we can click the reload button to reload our extension.
reload_button = shadow_root3.find_element(:tag_name, "cr-icon-button")
reload_button.click # click first reload button
What if I have more than one extensions to reload?
In this scenario, I only had one extension to reload, so I stopped there. In the case of multiple extensions you will want to continue using shadow_root2
to locate each extension and their corresponding shadow root.
Return to the Extension’s Page
Again, referencing the prior tutorial (Drive Chrome with Extensions using Selenium WebDriver), use the extension’s ID to return to the extension’s page.
driver.get("chrome-extension://idgpnmonknjnojddfkpgkljpfnnfcklj/popup.html")
And presto! ModHeader has now loaded correctly and from here, you may continue testing with the aid of Chrome extensions.
Here is a gif of the start of my cookie test running:
The Code
As you only need to reload extensions once, I recommend putting it in the before(:all) call. I have included the full code of my before(:all) below:
before(:all) do
@driver = $driver = Selenium::WebDriver.for(browser_type, browser_options)
driver.manage().window().resize_to(1280, 720) # first shadow root, call from driver
elem1 = driver.find_element(:tag_name, "extensions-manager")
shadow_root1 = driver.execute_script("return arguments[0].shadowRoot", elem1) # second shadow_root, call from shadow_root1
elem2 = shadow_root1.find_element(:tag_name, "extensions-item-list")
shadow_root2 = driver.execute_script("return arguments[0].shadowRoot", elem2) # third shadow_root, call from shadow_root2
elem3 = shadow_root2.find_element(:tag_name, "extensions-item")
shadow_root3 = driver.execute_script("return arguments[0].shadowRoot", elem3) # click reload button
reload_button = shadow_root3.find_element(:tag_name, "cr-icon-button")
reload_button.click driver.get(site_url)
end
Note: it would be a good idea to refactor the extension reload section out in a real project.