2.0.0 • Published 1 year ago

food-runner v2.0.0

Weekly downloads
-
License
AGPL-3.0-only
Repository
-
Last release
1 year 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:

  • Mocks for browser features, so you can run automated tests on your code in a Javascript server instead of a browser.
  • An RPC-like interface to the browser's message-passing systems, so you can express inter-context communications more easily, like those between pages, or even other extensions.
  • A context system that lets you emulate multiple pages and extensions at the same time while testing.
  • Utilities for dealing with raw binary data easily and efficiently, including:
    • serialization and deserialization using BSON
    • encoding and decoding using base 64
  • High-level utilities for working with persistent browser storage.
  • Tryout: a utility getting rapid visual feedback when developing UI views

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 package manager using the package name:

food-runner

Creating a service

On your extension's background page:

import runner from 'food-runner';

export class TestService {

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

runner.server.serveInternal(new TestService());

Using a service

On your extension's application page:

import runner from 'food-runner';

/** @type {TestService} */
const service = await runner.client.get();
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 runner from 'food-runner';

export class TestService {

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

runner.server.serveExternal(new TestService());

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

import runner from 'food-runner';

/** @type {TestService} */
const service = await runner.client.get('server');
const greeting = await bg.greet(browser.runtime.id);

// greeting should be 'hello, client'

Running tests using services

Use the Food Runner globals API to switch window and browser global mocks as necessary. If you're using Jasmine to express tests, try something like this:

import runner from 'food-runner';
import * as globals from 'food-runner/testlib/globals.js';

describe("My Tests", () => {
    
    it("test a service", async () => {
        
        // create a context for the extension background page
        const extId = 'ext';
        const ext = globals.create(extId);
        await ext.run('test/scripts/background.js');
         
        // become the context for a browser tab holding an extension page
        const tabId = 5;
        globals.create(extId, tabId).replace();
        
        // use the service on the background page
        const bg = await runner.client.get();
        await bg.doAThing();
    });
});

More examples

For more examples, see the extensive test suite.

Limitations

Since Javascript has no good way to express asynchronous property getters and setters, only function calls are relayed between contexts. Properties on the server side will not be accessible to the client side.

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) 2022 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/.

2.0.0

1 year ago

1.0.0

1 year ago