UI test utils
This package presents UI functions that you can invoke to simplify plugin testing. It requires an environment like jest or jasmine that has the beforeEach symbol defined globally.
Installation
These test utils are packed as a part of the @orion/ui module. You only need to import like: import { test-utils you need } from @orion/ui/test-utils on your tests in order to be able to use them.
renderPOSComponent
Plugins use POSComponents to define views inside the application. In your tests, you want to test those POSComponents. The function renderPOSComponent renders a POSComponent of the given name.
import { renderPOSComponent } from '@orion/ui/test-utils';
function<Helper> renderPOSComponent(
componentName: string,
props?: object,
children?: React.ReactNode,
): RenderResult
Arguments:
-
componentName: is the component name to render,
-
props (optional): props to pass to that component.
-
children (optional): children to pass to that component.
The result is the corresponding object for the render method of the @testing-library/react.

The initial count is 0. The button increments the count in 1. The button accumulates increments multiple times.
spec.js
import { addPlugin, useKernels } from '@orion/core/test-utils';
import { renderPOSComponent } from '@orion/ui/test-utils';
import { uiKernel } from '@orion/ui';
import { getByText } from '@testing-library/dom';
import VisualCounterPlugin from './VisualCounterPlugin.js';
import pkg from './package.json';
let counterComponent;
beforeEach(() => {
useKernels(uiKernel);
addPlugin(pkg, VisualCounterPlugin);
counterComponent = renderPOSComponent('Counter').container;
});
test('The initial count is 0', () => {
expect(counterComponent.textContent).toMatch('[0]');
});
test('The button increments the count in 1', () => {
const button = getByText(counterComponent, 'increment');
button.click();
expect(counterComponent.textContent).toMatch('[1]');
});
test('The button accumulates increments multiple times', () => {
const button = getByText(counterComponent, 'increment');
button.click();
button.click();
button.click();
expect(counterComponent.textContent).toMatch('[3]');
});
VisualCounterPlugin.js
import React from 'react';
const INCREMENT = 'visual-counter-plugin/INCREMENT';
const increment = () => ({ type: INCREMENT });
const reduceCounter = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
return state + 1;
default:
return state;
}
};
function getCount(state) {
return state.plugins.counter;
}
const CounterDisplay = ({ number, increment }) => (
<div>
Count [{number}] <button onClick={increment}>increment</button>
</div>
);
const makeCounter = ({ uiHelper }) => {
const mapStateToProps = (state) => ({
number: getCount(state),
});
const mapDispatchToProps = { increment };
return uiHelper.posConnect(mapStateToProps, mapDispatchToProps)(CounterDisplay);
};
export default class VisualCounterPlugin {
constructor(dio) {
dio.uiHelper.putComponent('Counter', makeCounter(dio));
dio.storeHelper.registerReducer('counter', reduceCounter);
}
}
package.json
{
"name": "visual-counter-plugin",
"version": "1.0.0"
}
renderPluginComponent
Plugins can define their custom Components to define views inside the application. In your tests, you want to test those Components. The function renderPluginComponent renders a Component registered by a plugin.
import { renderPluginComponent } from '@orion/ui/test-utils';
function renderPluginComponent(
plugin: Plugin,
componentName: string,
props?: object,
children?: React.ReactNode,
): RenderResult;
Arguments:
-
plugin: is the instance of the plugin producing the Component.
-
componentName: is the name of the component to render.
-
props (optional): props to pass to that component.
-
children (optional): children to pass to that component.
The result is the corresponding object for the render method of the @testing-library/react.

The initial count is 0. The button increments the count in 1. The button accumulates increments multiple times.
spec.js
import { addPlugin, useKernels } from '@orion/core/test-utils';
import { renderPluginComponent } from '@orion/ui/test-utils';
import { uiKernel } from '@orion/ui';
import { getByText } from '@testing-library/dom';
import VisualCounterPlugin from './VisualCounterPlugin.js';
import pkg from './package.json';
let counterComponent;
beforeEach(() => {
useKernels(uiKernel);
const plugin = addPlugin(pkg, VisualCounterPlugin);
counterComponent = renderPluginComponent(plugin, 'Counter').container;
});
test('The initial count is 0', () => {
expect(counterComponent.textContent).toMatch('[0]');
});
test('The button increments the count in 1', () => {
const button = getByText(counterComponent, 'increment');
button.click();
expect(counterComponent.textContent).toMatch('[1]');
});
test('The button accumulates increments multiple times', () => {
const button = getByText(counterComponent, 'increment');
button.click();
button.click();
button.click();
expect(counterComponent.textContent).toMatch('[3]');
});
store/counter.js
export const INCREMENT = 'visual-counter-plugin/INCREMENT';
export const increment = () => ({ type: INCREMENT });
export const reduceCounter = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
return state + 1;
default:
return state;
}
};
export function selectCount(state) {
return state.plugins.counter;
}
hooks.js
import { createContext, useContext } from 'react';
export const HooksContext = createContext(null);
export function useHooks() {
return useContext(HooksContext);
}
export function useSelector(selector, equalityFn) {
const hooks = useHooks();
return hooks.useSelector(selector, equalityFn);
}
export function useDispatch() {
const hooks = useHooks();
return hooks.useDispatch();
}
components/Counter.js
import React, { useCallback } from 'react';
import { selectCount, increment } from '../store/counter.js';
import { useSelector, useDispatch } from '../hooks.js';
export function Counter() {
const dispatch = useDispatch();
const onClickIncrement = useCallback(() => dispatch(increment()), [dispatch]);
const number = useSelector(selectCount);
return (
<div>
Count [{number}] <button onClick={onClickIncrement}>increment</button>
</div>
);
}
VisualCounterPlugin.js
import { HooksContext } from './hooks.js';
import { reduceCounter } from './store/counter.js';
import { Counter } from './components/Counter.js';
export default class VisualCounterPlugin {
constructor({ uiHelper, storeHelper }) {
uiHelper.putHooksContext(HooksContext);
uiHelper.registerComponent('Counter', Counter);
storeHelper.registerReducer('counter', reduceCounter);
}
}
package.json
{
"name": "visual-counter-plugin",
"version": "1.0.0",
"orion": {
"uiHelper": {
"components": {
"produces": [
"Counter"
]
},
"hooks": {
"consumes": {
"@orion/ui": [
"useSelector",
"useDispatch"
]
}
}
}
}
}
render
The function render from @orion/ui/test-utils renders a React Element wrapping it inside all the configured Wrappers of the application (e.g., the Store Provider from Redux).
import { render } from '@orion/ui/test-utils';
function render(ui: React.ReactElement): RenderResult;
Arguments:
-
ui: is the React Element to be rendered inside the Application wrappers
The result is the corresponding object for the render method of the @testing-library/react.

Renders the component inside the App Wrappers
spec.js
import React from 'react';
import { screen } from '@testing-library/react';
import { configure } from '@orion/core/test-utils';
import { render } from '@orion/ui/test-utils';
import { getByText } from '@testing-library/dom';
function HelloWorld() {
return <div>Hello World!</div>;
}
test('renders the component inside the App Wrappers', () => {
function App({ children }) {
return <div data-testid="app-wrapper">{children}</div>;
}
configure(({ coreAppManagerProvider }) => {
coreAppManagerProvider.addWrapper(App);
});
render(<HelloWorld />);
const appWrapper = screen.getByTestId('app-wrapper');
expect(appWrapper).toBeDefined();
expect(getByText(appWrapper, 'Hello World!')).toBeDefined();
});
GAST
There is no special function to render GAST. GAST components are POSComponents like the React ones. No special API is required.

The initial count is 0. The button increments the count in 1. The button accumulates increments multiple times.
spec.js
import { addPlugin, useKernels } from '@orion/core/test-utils';
import { renderPOSComponent } from '@orion/ui/test-utils';
import { getByText } from '@testing-library/dom';
import { gastKernel } from '@orion/gast';
import VisualCounterPlugin from './VisualCounterPlugin.js';
import pkg from './package.json';
let counterComponent;
beforeEach(() => {
useKernels(gastKernel);
addPlugin(pkg, VisualCounterPlugin);
counterComponent = renderPOSComponent('Counter').container;
});
test('The initial count is 0', () => {
expect(counterComponent.textContent).toMatch('[0]');
});
test('The button increments the count in 1', () => {
const button = getByText(counterComponent, 'increment');
button.click();
expect(counterComponent.textContent).toMatch('[1]');
});
test('The button accumulates increments multiple times', () => {
const button = getByText(counterComponent, 'increment');
button.click();
button.click();
button.click();
expect(counterComponent.textContent).toMatch('[3]');
});
Counter.gast
<div>
Count [{getVM(`$.counter`, 0)}]
{' '}
<button onClick="
() => updateVM(`$.counter`, (count = 0) => count + 1)
">increment</button>
</div>
VisualCounterPlugin.js
import Counter from './Counter.gast';
export default class VisualCounterPlugin {
constructor({ gastHelper }) {
gastHelper.putGASTComponent('Counter', Counter);
}
}
package.json
{
"name": "gast-counter-plugin",
"version": "1.0.0",
"orion": {
"dispatchersHelper": {
"actionCreators": {
"consumes": {
"@orion/vm": [
"updateVM"
]
}
}
},
"selectorsHelper": {
"selectorFactories": {
"consumes": {
"@orion/vm": [
"getVM"
]
}
}
}
}
}