lurscher
lurscher

Reputation: 26953

unable to access chrome message passing API from selenium execute_script

I need to send a value to the chrome extension from the browser automation script. the way I'm currently attempting to do it is by trying to invoke the chrome.runtime.sendMessage API from selenium to communicate some value to a chrome extension. The python code is:

import os
import time
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options



chrome_options = Options()
chrome_options.add_extension('/home/lurscher/plugin.crx')
browser = webdriver.Chrome(chrome_options=chrome_options)
browser.get(url)
browser.execute_script("chrome.runtime.sendMessage({someValue: "+str(args.value)+"}, function(response) { console.log('value sent. '+response)})")

I get this error:

Traceback (most recent call last):
  File "tools/selenium/open_page.py", line 17, in <module>
    browser.execute_script("chrome.runtime.sendMessage({someValue: "+str(args.value)+"}, function(response) { console.log('value sent. '+response)})")
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 397, in execute_script
    {'script': script, 'args':converted_args})['value']
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 165, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py", line 164, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: u"unknown error: Cannot call method 'sendMessage' of undefined\n  (Session info: chrome=28.0.1500.71)\n  (Driver info: chromedriver=2.1,platform=Linux 3.5.0-17-generic x86_64)" 

Question: Any idea what I'm doing wrong?

I need to send a value to the chrome extension from the browser automation script. How Do I Do It?

Upvotes: 7

Views: 2538

Answers (4)

customcommander
customcommander

Reputation: 18901

Got a similar error when running this: (JavaScript)

this.driver.executeScript(function () {
    chrome.runtime.sendMessage('start');
});
WebDriverError: unknown error: Cannot read property 'sendMessage' of undefined

It seems to me that chrome.runtime is always available regardless of whether you’re developing extensions or just browsing the web. (Open an Incognito window and evaluate it in the console; it’s there.) So it has to be something to do with WebDriver.

From what I could gather on the interwebs, you must extra configure your driver: https://groups.google.com/forum/#!topic/chromedriver-users/7wF9EHF2jxQ

options.excludeSwitches('test-type'); // this makes chrome.runtime available
builder.setChromeOptions(options);

However this makes the above error evolves into:

WebDriverError: unknown error: Invalid arguments to connect.

That’s because your test page is trying to communicate with your extension which isn’t allowed as per the Chrome specs unless you declare that page in your manifest. e.g.:

"externally_connectable": {
    "matches": [
    "http://localhost:8000/mytest.html”
    ]
}

However you must now include the extension id in your sendMessage call:

this.driver.executeScript(function () {
    chrome.runtime.sendMessage('kjnfjpehjfekjjhcgkodhnpfkoalhehl', 'start');
});

Which I think is a bit awkward.

I would recommend something along the lines of what MGR has suggested that is using a content script to proxy your sendMessage call as content scripts don’t have the restriction imposed on external pages.

What I did was to trigger an event from my tests that would be picked up by a content script which is the one making the sendMessage function call:

In your tests:

this.driver.executeScript(function () {
    var event = document.createEvent('HTMLEvents');
    event.initEvent('extension-button-click', true, true);
    document.dispatchEvent(event);
});

Declare a content script in your manifest:

"content_scripts": [
    { "matches": ["<all_urls>"], "js": ["content_script.js"] }
]

And in content_script.js:

document.addEventListener('extension-button-click', function () {
    chrome.runtime.sendMessage('start');
});

Hope it helps

Upvotes: 2

MGR
MGR

Reputation: 323

There may be more than one solution for this question. But I would suggest the usage of a content script page to your extension and communicate using the function inside the content script. As content script form a client side part, you can access the functions defined within the content script to communicate to the extension without any issues. Let me know, if this is not suitable for you.

Upvotes: 0

Khamidulla
Khamidulla

Reputation: 2975

As far as I understand from your selenium python code you want to send data to google chromes extension. It is not possible. You do not have permission and Chrome will not allow you todo so. Unless you will create some hidden html element for example any element with id = 'message' and send parameters in data attributes or as value of element. And create Contents Script in your Google Chrome extension which will be injected to page after page is loaded. After Contents Script will be injected to the page you can obtain your parameters through given ID.

Upvotes: 0

Kinka
Kinka

Reputation: 425

As the exceptions message says, Cannot call method 'sendMessage' of undefined. It seems that chrome.runtime call only be called in the contenxt of chrome extensions, and the code excuted in execute_script is just in the context of your page.

Upvotes: 0

Related Questions