The onMessage listener in Chrome consistently returns an 'undefined' response

My latest project involves creating a simple chrome extension that utilizes message passing. The goal of the extension is to listen for messages from a specific website (in this case, localhost:8080/*) and respond with a simple "Bye". To test this functionality, Selenium opens a locally served page in Chrome, attempts to send a message to the extension, and then displays the response in the console:

$ 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();
    });
});

To run a test first run a local http server

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

and from another console run the tests

$ npm test

> <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="27444f55484a420a53425453671709170912">[email protected]</a> 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/prompt...
      

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

The extension always responds undefined instead of 'Bye' as instructed in background.js.

Answer №1

Incorrect Event.

When messages are sent from webpages using externally_connectable, they are categorized as external messages. Therefore, your background script should be configured like this:

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

The issue you are facing is due to the listener sending an undefined response. This happens when the callback of sendMessage is triggered by one of two scenarios:

  • A listener actually utilizes sendResponse. In this case, the argument will contain that response.
  • If there was an error sending the message, the argument will be undefined, and chrome.runtime.lastError will be set.

In your situation, you are encountering the second scenario - where there is no listener for the specific event.

It raises the question of whether the webpage context has access to chrome.runtime.lastError.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountering difficulty with locating a button element within an HTML form using Selenium WebDriver in C#

Full HTML Code How do I access the button identified by the id(export_but)? The image shows the HTML code of a form tag that appears when a button is clicked. I have tried various methods such as XPath, CssSelector, and Id to locate this element. This p ...

Tips for implementing React Browser Router within Material UI Drawer

I'm currently exploring how to implement Browser Router in React to populate the content section of a Material UI Drawer. While my code successfully links menu options to components displayed within the drawer's content section, a problem arises ...

Executing a nested function before moving on to the subsequent code statements

I have a requirement where certain functions in my codebase need to check if a user is logged in before proceeding. Instead of duplicating this check logic, I want to call a single getUser() function each time. Here is the order of operations for the func ...

The 'file' property of undefined throws an error in ng-file-upload

I am currently exploring the functionality of ng-file-upload from this repository: https://github.com/danialfarid/ng-file-upload I have successfully implemented the basic setup as follows: HTML: <section ng-controller="MyController"> ...

Warning in Next.js: When utilizing conditional rendering, the server HTML is expected to have a corresponding <div> inside another <div>

Although similar questions have been asked on various platforms like Google, none seem to provide answers that align with my specific situation. Essentially, my goal is to have a different search bar displayed in the header based on the page I am currentl ...

What is the most effective approach for addressing errors in both the server and client sides while utilizing nodejs and express?

Seeking the most effective approach for handling errors in a response - request scenario. Here is an example of a route that receives a request: app.get('/getInfo', function (req, res, next) { let obj = {} try { obj = { ...

Is there a way to adjust the quantity of items in the shopping cart without the need to reload the webpage?

Currently, I am working on a test project using React & Redux. The project involves implementing a basket feature where I receive an array of products structured like this: products: [ { name: "Product one", count: 1, ...

Error encountered when calling the function .jstree() on a tree structure

While working on MVC4, I attempted to implement a jstree but encountered an issue where the tree view was not displayed when running my application. Upon investigating with Firebug, I came across the following error message: "TypeError: $(...).jstree is ...

Embed a React component within another component

Recently, I've started learning React and I'm utilizing material-ui for my project. My goal is to create a customized autocomplete feature in React where selected data from the dropdown will appear as chips inside the text input field. I am curre ...

What is the process for removing the body of a table?

My goal is to reset the table body, which has been filled with JavaScript loaded data previously. https://i.stack.imgur.com/7774K.png ` getTableData = function (clicked_id) { if (clicked_id != '') { $.ajax({ async : f ...

Is it possible for the Chrome debugger to locate TypeScript files that have not been served by the

I am creating .js.map files to assist in debugging my TypeScript code within Chrome. The js.map files specify the correct location of the TypeScript in the "sources" property. sourceRoot is set to "", and sources represent the path to the TypeScript code ...

Extracting information from HTML and transferring it to Javascript using jQuery

My goal is to utilize jsGrid for showcasing database data without repeating code extensively. I aim to generate separate grids for each <div> with a specific id while passing on relevant values accordingly. To clarify my objective, here's a sni ...

Issue with Sequential Drop Down List Functionality in ASP.Net MVC View Page

I am currently in the process of migrating code from one project to another. Although the code works fine in the original project, it is not functioning properly in the new one. I’m uncertain if something was overlooked on my end. Within this code, ther ...

Using a physical Android device to test and run a Meteor mobile application

I'm struggling to get my Meteor app to run on my Android device (LG G2). Despite searching online for a solution, I haven't come across any similar issues. I followed the instructions carefully, added the Android platform to my project, and ran i ...

A step-by-step guide on verifying all currently open windows in Chrome and their titles using Selenium

I am facing an issue in Chrome where 3 windows are opened, but without closing any window, I need to check the title of the last open window. I have tried using `driver.getTitle();` but it is returning the title of the first window instead. The reason fo ...

Is there a way to retrieve the class value and store it in a CSV file using Selenium?

Is there a way to extract and store a value using selenium with Python? I am aiming to save this value in a CSV file. Here is what I have attempted: #element= driver.find_element_by_xpath("//*[@class='rt-tr-group']") elements = driver ...

Mastering the usage of AngularJS Directive controllerAs syntax with scope is key to developing

I have included my code below: // HTML <body> <h1>{{foo.name}}</h1> <my-directive></my-directive> </body> // Scripts app.directive('myDirective', function() { return { restrict: 'E', ...

Creating a form with multiple checkboxes using Material-UI components where only a single checkbox can be selected

Creating a simple form using Material-UI with checkboxes to select one option and push data to the backend on submit is the goal. The Form component structure includes: multiple options represented by checkboxes only one checkbox can be selected at a time ...

Handling error reporting using JSON in jQuery AJAX post success

UPDATE: I have resolved the PHP errors mentioned in previous Answers, however, the issue still persists. I am attempting to implement an error message display in case of a failed POST request and a success message for successfully completed requests. Curr ...

How do I save the value of a callback function in Vue data?

#I am facing an issue where the value of this.zuobiao is not being logged after I call the function that assigns a value to it. Why is this happening? getUserProfile() { uni.getLocation({ type: 'gcj02 ', geocode: true, success: (res) => ...