Слушатель Chrome onMessage всегда отправляет ответ «неопределенный»

Я сделал самое простое расширение для Chrome, которое может использовать передачу сообщений. Расширение должно прослушивать сообщения с веб-сайта (localhost:8080/* здесь) и всегда отвечать "Пока". В тесте селен открывает локально обслуживаемую страницу с хромом, который пытается отправить сообщение расширению, а затем выдает ответ на консоль:

$ tree -I node_modules
.
├── extension
│   ├── background.js
│   └── manifest.json
├── package.json
└── test
    ├── index.html
    └── selenium-test.js

2 directories, 5 files

background.js

chrome.runtime.onMessage.addListener(
    function (req, sender, sendResp) {
        sendResp('Bye');
    });

manifest.json

{
    "name": "chrome-test",
    "version": "0.1",
    "manifest_version": 2,
    "key": "pcoogjpilcclcmejpkmbifdbihomlgec",
    "description": "Test extension.",
    "app": {
    "background": {
        "scripts": ["background.js"],
        "persistent": true
    }
    },
    "externally_connectable": {
    "matches": [
        "http://localhost:8080/*"
    ],
    "accepts_tls_channel_id": false
    },
    "permissions": [
    "http://localhost:8080/*"
    ]
}

package.json

{
    "name": "chrome-test",
    "version": "0.0.5",
    "description": "Chrome API sucks.",
    "keywords": [ "" ],
    "author": "Chris Perivolaropoulos",
    "contributors": [],
    "dependencies": {
    "selenium-webdriver": "*",
    "mocha": "*",
    "chai": "*"
    },
    "scripts": {
    "test": "mocha test/selenium-test.js"
    }
}

index.html

<html>
  <head>
    <title>Test page</title>
  </head>
  <body>
    <h1>Test page</h1>
    <div id="echo"></div>
    <script type="text/javascript">
      chrome.runtime.sendMessage('pcoogjpilcclcmejpkmbifdbihomlgec', 'hello',
      function (msg) {
      console.log("Received! " + msg);
      });
    </script>
  </body>
</html>

selenium-test.js

var assert = require('chai').assert,
    test = require('selenium-webdriver/testing'),
    webdriver = require('selenium-webdriver'),
    chromedriver = require('selenium-webdriver/chrome');

// @param extensions: string of unpacked extension path to install.
function chrome_driver(extension) {
    var logperfs = new webdriver.logging.Preferences(),
            opts = new chromedriver.Options().
                addArguments("--load-extension=" + extension ||
                                         '../extension');

    logperfs.setLevel(webdriver.logging.Type.BROWSER,
                                        webdriver.logging.Level.ALL);

    var chrome = new webdriver.Builder().
                withCapabilities(webdriver.Capabilities.chrome()).
                setChromeOptions(opts).
                setLoggingPrefs(logperfs).
                build();

    chrome.manage().timeouts().pageLoadTimeout(5000);
    return chrome;
}

function browser_logs(driver, callback) {
    driver.manage().logs().
        get(webdriver.logging.Type.BROWSER).then(callback);
}

test.describe('Test', function() {
    var chrome;
    this.timeout(10000);

    test.before(function() {
        chrome = chrome_driver("extension");
    });

    test.it("Test messages", function () {
        chrome.get("http://localhost:8080/test/index.html").then(function () {
            browser_logs(chrome, function (entries) {
                entries.forEach(function (e) {console.log("BrowserLog: " + e.message);});
                assert.equal(entries.pop().message,
                                         "hello", "Bus not echoing.");
            });
        });
    });

    test.after(function() {
        chrome.quit();
    });
});

Чтобы запустить тест, сначала запустите локальный http-сервер.

$ python -m SimpleHTTPServer 8080
Serving HTTP on 0.0.0.0 port 8080 ...

и с другой консоли запустить тесты

$ npm test

> [email protected] test /path/to/project
> mocha test/selenium-test.js



  Test
BrowserLog: http://localhost:8080/test/index.html 11:15 Received! undefined
[2K[0G    1) Test messages


  0 passing (1s)
  1 failing

  1) Test Test messages:

      Bus not echoing.
      + expected - actual

      +hello
      -http://localhost:8080/test/index.html 11:15 Receviced! undefined

      at /path/to/project/test/selenium-test.js:43:12
      at /path/to/project/node_modules/selenium-webdriver/lib/goog/base.js:1582:15
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1640:20)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at Object.webdriver.promise.asap (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:758:5)
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1651:25)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at Object.webdriver.promise.asap (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:758:5)
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1651:25)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at /path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1507:10
      at /path/to/project/node_modules/selenium-webdriver/lib/goog/base.js:1582:15
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1640:20)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at /path/to/project/node_modules/selenium-webdriver/lib/goog/base.js:1582:15
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1640:20)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at /path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:703:49
      at /path/to/project/node_modules/selenium-webdriver/lib/webdriver/http/http.js:96:5
      at IncomingMessage.<anonymous> (/path/to/project/node_modules/selenium-webdriver/http/index.js:131:7)
      at IncomingMessage.emit (events.js:117:20)
      at _stream_readable.js:943:16
      at process._tickCallback (node.js:419:13)
  ==== async task ====
  WebDriver.manage().logs().get(browser)
      at webdriver.WebDriver.schedule (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/webdriver.js:302:15)
      at webdriver.WebDriver.Logs.get (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/webdriver.js:1380:23)
      at browser_logs (/path/to/project/test/selenium-test.js:28:3)
      at /path/to/project/test/selenium-test.js:41:4
      at /path/to/project/node_modules/selenium-webdriver/lib/goog/base.js:1582:15
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1640:20)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at Object.webdriver.promise.asap (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:758:5)
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1651:25)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at /path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1507:10
      at /path/to/project/node_modules/selenium-webdriver/lib/goog/base.js:1582:15
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1640:20)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at /path/to/project/node_modules/selenium-webdriver/lib/goog/base.js:1582:15
      at webdriver.promise.ControlFlow.runInNewFrame_ (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:1640:20)
      at notify (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:444:12)
      at notifyAll (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:422:7)
      at resolve (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:400:7)
      at fulfill (/path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:512:5)
      at /path/to/project/node_modules/selenium-webdriver/lib/webdriver/promise.js:703:49
      at /path/to/project/node_modules/selenium-webdriver/lib/webdriver/http/http.js:96:5
      at IncomingMessage.<anonymous> (/path/to/project/node_modules/selenium-webdriver/http/index.js:131:7)
      at IncomingMessage.emit (events.js:117:20)
      at _stream_readable.js:943:16
      at process._tickCallback (node.js:419:13)
  ==== async task ====
      at Context.ret (/path/to/project/node_modules/selenium-webdriver/testing/index.js:132:12)
      at Test.Runnable.run (/path/to/project/node_modules/mocha/lib/runnable.js:216:15)
      at Runner.runTest (/path/to/project/node_modules/mocha/lib/runner.js:373:10)
      at /path/to/project/node_modules/mocha/lib/runner.js:451:12
      at next (/path/to/project/node_modules/mocha/lib/runner.js:298:14)
      at /path/to/project/node_modules/mocha/lib/runner.js:308:7
      at next (/path/to/project/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/path/to/project/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:345:15)



npm ERR! Test failed.  See above for more details.

Расширение всегда отвечает undefined вместо 'Bye', как указано в background.js.


person fakedrake    schedule 08.10.2014    source источник
comment
Я думаю, вы запутались. onMessage: запускается, когда сообщение отправляется либо из процесса расширения, либо из скрипта содержимого. developer.chrome.com/extensions/runtime#event-onMessage   -  person Marc Guiselin    schedule 08.10.2014
comment
Ну да, и он также может отправить один ответ с sendResp. Я изменил этот ответ с «привет» на «пока» для ясности.   -  person fakedrake    schedule 08.10.2014


Ответы (1)


Неверное событие.

Сообщения, отправленные с веб-страниц через externally_connectable, считаются внешними сообщениями. . Поэтому ваш фоновый скрипт должен выглядеть таким образом:

chrome.runtime.onMessageExternal.addListener(
  function (req, sender, sendResp) {
    sendResp('Bye');
  }
);

Создается впечатление, что слушатель отправляет неопределенный ответ, потому что обратный вызов sendMessage вызывается в одном из двух случаев:

  • Слушатель на самом деле позвонил sendResponse. Затем аргумент устанавливается для этого ответа.
  • Произошла ошибка при отправке сообщения. Тогда аргумент равен undefined и устанавливается chrome.runtime.lastError.

Вы попадаете во второй случай - так как не было слушателя для соответствующего события.

Теперь отдельный вопрос заключается в том, получает ли контекст веб-страницы доступ к chrome.runtime.lastError..

person Xan    schedule 08.10.2014
comment
Это сработало, большое спасибо. РЕДАКТИРОВАТЬ: да, похоже, что веб-страница имеет доступ к lastError - person fakedrake; 08.10.2014