Why do we need a plugin system?
There is a lot of amazing functionality that can be built on top of ekke. It runs inside React-Native but communicates with Nodejs using WebSocket connection. So in reality, you can have best of both worlds. My go-to example for a plugin is: screenshots. With ekke we have a render() method that renders your component on screen. We could implement a screenshot API by calling the adb shell screencap -p command on the CLI, run visual diffing against it using pixelmatch and stream back the result for an assertion. Or maybe you just want to create a plugin that allows you to interact with the file system to read files or even data directly from React-Native.
As neat as all these features are, they should not belong in the core of ekke, but we should provide a programmable API that makes this possible. In fact, if we do this correctly, even our test runners could technically be plugins, but included by default.
Plugin requirements
It needs to have an API that can communicate, we already have a WebSocket bridge which we can expose. This way plugins can:
- File System interaction storing files, retrieving files.
- Starting / Stopping servers, we don't have HTTP servers in RN.
- Executing of CLI processes, maybe you want to interact with the
adb command and create a screenshot of the device.
- Anything you would do in Node.js basically
It's not just communication with Node.js that is required, plugins should be able to modify every part of our orchestration:
- Modify our babel configuration. e.g. adding plugins and presets.
- Modify the created Metro configuration. Allow them to override our defaults.
- Introduce new methods to our API/CLI.
- Include files in the test bundle. So it requires it's own libraries that need to be bundled.
- Execute before, after, test execution. Setup additional hooks, polyfills, anything.
- Intercept, and modify test runners. Maybe introduce new config, or call additional API methods.
- Intercept error/test failures.
The plugin API should be simple, async, and event-based. It's would not be uncommon that multiple plugins leverage the same API and by making it even based, each individual plugin can subscribe to the events. This also allows us to make the bridge function, event-based, so they can subscribe to the events they execute.
Plugin API when required in Node.js (use main in the package.json)
export default function myPlugin({ modify, bridge, register }) {
modify('babel', async function (babel) {
return require('babel-merge')(babel, customconfig);
});
modify('metro.config', async function (metro) {
return require('metro-config').merge(metro, { custom });
});
bridge('screenshot', async function (id, reply) {
const { old, new } = await makescreenshot(id);
const diff = await compare(old, new);
await reply(diff);
});
//
// Registers a new method on the `API`.
//
register('method', async function () {
});
}
Plugin API when required in React-Native (use react-native in the package.json)
export default function myPlugin({ subscribe, bridge, register }) {
modify('setup', async (runner) {
// do stuff
});
//
// Introduces new method on for the `plugin()` API.
//
register('screenshot', async function (element, name) {
const id = name || (element.type +'@'+ JSON.stringify(props));
await render(element);
return await bridge('screenshot', id);
}
});
});
Plugin API as consumed by users.
import { render, bridge, plugin } from 'ekke';
const { screenshot } = plugin('example');
it('takes a screenshot', async function () {
await render(<Component />);
const diff = await screenshot(<Component />);
assume(diff).is.a('object')
});
Acceptance Criteria
Why do we need a plugin system?
There is a lot of amazing functionality that can be built on top of
ekke. It runs inside React-Native but communicates with Nodejs using WebSocket connection. So in reality, you can have best of both worlds. My go-to example for a plugin is: screenshots. Withekkewe have arender()method that renders your component on screen. We could implement a screenshot API by calling theadb shell screencap -pcommand on the CLI, run visual diffing against it usingpixelmatchand stream back the result for an assertion. Or maybe you just want to create a plugin that allows you to interact with the file system to read files or even data directly from React-Native.As neat as all these features are, they should not belong in the core of ekke, but we should provide a programmable API that makes this possible. In fact, if we do this correctly, even our test runners could technically be plugins, but included by default.
Plugin requirements
It needs to have an API that can communicate, we already have a WebSocket
bridgewhich we can expose. This way plugins can:adbcommand and create a screenshot of the device.It's not just communication with Node.js that is required, plugins should be able to modify every part of our orchestration:
The plugin API should be simple, async, and event-based. It's would not be uncommon that multiple plugins leverage the same API and by making it even based, each individual plugin can subscribe to the events. This also allows us to make the
bridgefunction, event-based, so they can subscribe to the events they execute.Plugin API when required in Node.js (use
mainin thepackage.json)Plugin API when required in React-Native (use
react-nativein thepackage.json)Plugin API as consumed by users.
Acceptance Criteria
{ bridge }method that can be used to communicate with the CLI.--plugin <name>flag in our CLI/API that will require and initialize our plugins.ekkeAPI's are unit tested