Skip to main content

@storyshots/arrangers

Functions and utilities for working with externals during the arrange phase of stories.

createArrangers

Creates core utilities and binds them to the base externals type:

import { createArrangers } from '@storyshots/arrangers';

interface IExternals {
analytics: {
log(event: string): void;
};
business: {
getBalanceAt(date: number): Promise<number>;
applyCV(form: unknown): Promise<void>;
};
route: string;
}

const utils = createArrangers<IExternals>();

set

Sets a value for the specified key:

it('...', {
// The getBalanceAt method now has a different implementation
arrange: set('business.getBalanceAt', async () => 100_000),
});

record

Makes the provided methods trackable:

it('...', {
// Calls to getBalanceAt are now recorded in the log
arrange: record('business.getBalanceAt'),
});

Also accepts an implementation:

it('...', {
// In addition to recording, the behavior is also set
arrange: record('business.getBalanceAt', async () => 100_000),
});

transform

Transforms the return value of a method:

it('...', {
arrange: transform('business.getBalanceAt', (balance) => balance * 2),
});
note

Works only with async functions. For all others, use compose

compose

Sets a new value based on the current one:

it('...', {
arrange: compose('route', (path) => (path === '/login' ? '/' : path)),
});

focus

Focuses arrangers on a nested property:

import { createArrangers } from '@storyshots/arrangers';

interface IExternals {
repositories: {
UserRepository: {
getUser(): Promise<void>;
};
};
route: string;
}

const utils = createArrangers<IExternals>();

// Create arrangers focused on repositories.
export const repository = utils.focus('repositories');

The created utilities can then be used in stories as follows:

it('...', {
// The property path is now shortened
arrange: repository.set('UserRepository.getUser', async () =>
createAdminUserStub(),
),
});

arrange

Function that combines multiple arrangers into one:

it('...', {
arrange: arrange(
set('business.getBalanceAt', () => 100_000),
record('analytics.log'),
),
});

arrange can be nested within each other:

it('...', {
arrange: arrange(withZeroBalance(), withApplyCVSuccess()),
});

function withZeroBalance() {
return set('business.getBalanceAt', () => 0);
}

function withApplyCVSuccess() {
return arrange(
set('business.applyCV', async () => 'success'),
record('business.applyCV'),
);
}

Inline arrange can also be defined:

it('...', {
arrange: arrange(
set('business.getBalanceAt', () => 0),
// Can be extracted into a separate function
(externals) => {
clock.set(new Date(/* ... */));

return externals;
},
),
});

resolves

Creates a function that returns Promise.resolve with the provided value:

it('...', {
arrange: set('business.getBalanceAt', resolves(0)),
});

rejects

Creates a function that returns Promise.reject with the provided value:

it('...', {
arrange: set('business.getBalanceAt', rejects('Balance not found')),
});