3.0.1 • Published 11 months ago

food-runner v3.0.1

Weekly downloads
-
License
AGPL-3.0-only
Repository
-
Last release
11 months ago

Food Runner

Tools for building web apps inside of browser extensions

Introduction

Food Runner provides solutions for a lot of thorny problems you might run into while developing web apps that are designed to work inside of browser extensions.

Food Runner offers the following features:

  • Tools for building and running tests inside a real browser, instead of running against mocks in a server like Node.js
  • An RPC-like interface to the browser's message-passing systems, so you can express inter-context communications more easily. Connect to your extension's background page from:
    • Your extension pages
    • Extension pages from a different extension
    • A regular web page on any website
  • Utilities for dealing with raw binary data easily and efficiently, including:
    • Utility functions for creating, transforming, and comparing buffers
    • Encoding and decoding buffers using base 64
    • Serialization and deserialization using protocol buffers
  • Tools for defining custom protocol handlers
  • Utility functions for:
    • persistent browser storage
    • iterators
      • eg, call chaining like map, filter
      • both sync and async friendly!
    • arrays
    • promises
    • errors

Wait, what? What's a food runner?

In the restaurant industry, a food runner is the person who brings food from the kitchen to the table. They're a kind of communication channel between a restaurant's guests and its operators.

It seemed like a good metaphor for a piece of software whose main job is to facilitate communication between front-end and back-end pages in a browser extension.

Getting Started

Install the package using your favorite JavaScript package manager using the package name:

food-runner

Creating a service

On your extension's background page:

import { server } from 'food-runner/src/comlink.js';

export class TestService {

    /**
     * @param {string} name
     * @returns {Promise.<string>}
     */
    async greet(name) {
        return 'hello, ' + name;
    }
}

server.internalService = new TestService();
server.start();

FoodRunner's service system is based on (a heavily modified version of) the powerful Comlink library. Tragically, Comlink by itself won't work inside of browser extensions, but FoodRunner extends Comlink to work just as naturally inside browser extensions as anywhere else.

Using a service

On your extension's application page:

import { connect } from 'food-runner/src/comlink.js';

const service = /** @type {TestService} */ await connect();
const greeting = await bg.greet('bob');

// greeting should be 'hello, bob'

Using a service from a different extension

Let's assume the server extension's id is server, and that extension is running the background page:

import { server } from 'food-runner/src/comlink.js';

export class TestService {

    /**
     * @param {string} name
     * @returns {Promise.<string>}
     */
    async greet(name) {
        return 'hello, ' + name;
    }
}

server.externalService = new TestService();
server.start();

Note that we made the service external this time by assigning it to server.externalService.

Let's assume the client extension's id is client, running an extension page:

import { connect } from 'food-runner/src/comlink.js';

const service = /** @type {TestService} */ await connect('server');
const greeting = await bg.greet('client');

// greeting should be 'hello, client'

This time, we supplied an argument to connect() with the id of the server extension, server.

Running tests using services

FoodRunner provides tools for building your tests into browser extensions that you can temporarily load into your browser.

To use the build tools, add the food-runner-build package to your project in the devDependencies section. The FoodRunner build tools use Rollup to generate HTML pages with the Mocha test runner that you can run in your browser.

To build your tests, run a script like the following in your JavaScript build system (eg, Node.js):

import { collectTestFiles, buildTestExtension } from 'food-runner-build';

(async () => {
   await buildTestExtension(
     "my-extension-test@cuchaz",
     "My Extension Test",
     'build/extensions/test',
     {
        testFiles: await collectTestFiles('test/tests'),
        bgScript: 'test/bg.js'
     }
   );
})();

This will build your extension into the build/extensions/test folder and give it the id my-extension-test@cuchaz. collectTestFiles() will collect all the .js files you have in the test/tests folder and add them to the extension build, and the test runner. The background script in bgScript can be the real actual background script from your extension, or it can be a special background script just for testing.

The tests folder should contain JavaScript files that look like Mocha tests:

import { expect } from 'chai';

import { formatErrors } from 'food-runner/testlib/errors.js';

describe("my tests", function() {

    it("works", function() {
        expect(5).equal(5);
    });
});

You can use any assertion library you like, but the describe and it test scaffolding functions are already defined by Mocha.

More examples

For more examples, see the extensive test suite.

Documentation

This is a very new project. Documentation practically non-existent at the moment.

The source code itself has many JSDoc comments, and the Getting Started section above has some simple examples. That's about it so far.

If/when this project gets more attention, the documention will be improved.

License

Copyright (C) 2024 Cuchaz Interactive, LLC and contributors (see AUTHORS.md)

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.

3.0.1

11 months ago

3.0.0

1 year ago

2.0.0

2 years ago

1.0.0

3 years ago