Skip to content
This repository has been archived by the owner on Aug 13, 2023. It is now read-only.

Ability to create RTL variants of specific/all stories of a kind as substories #2453

Merged
merged 14 commits into from
Oct 23, 2019
1 change: 1 addition & 0 deletions packages/utilities/psammead-storybook-helpers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- prettier-ignore -->
| Version | Description |
|---------|-------------|
| 8.0.0 | [PR#2453](https://github.com/bbc/psammead/pull/2453) ability to create RTL variants of all stories of a specific kind or specific stories of specific kind |
| 7.0.1 | [PR#2436](https://github.com/bbc/psammead/pull/2436) Update chinese locales |
| 7.0.0 | [PR#2404](https://github.com/bbc/psammead/pull/2404) replace inputProvider and dirDecorator with withServicesInput |
| 6.2.0 | [PR#2407](https://github.com/bbc/psammead/pull/2407) adds buildRTLSubstories to create right-to-left variants of all stories |
Expand Down
21 changes: 17 additions & 4 deletions packages/utilities/psammead-storybook-helpers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ The `withServicesKnob` function accepts an options argument with 2 properties:
- `defaultService`(String): The default selected service of the services dropdown e.g. `arabic`. The default is `news`.
- `services`(Array): A list of services that the dropdown will display. The default is all services.

`buildRTLSubstories` - a function that gets all stories and creates right-to-left variants as substories. Internally it uses the `withServicesKnob` to set the default service as `arabic`. The appropriate place to use this function is in `storybook/config.js`.
`buildRTLSubstories` - a function to create right-to-left variants of stories as substories. Internally it uses the `withServicesKnob` to set the default service as `arabic`.

The `buildRTLSubstories` function accepts 2 arguments.

- `storyKind`(String) - This is the story kind that you want you want to create RTL substories from. This will normally be the first argument you pass into `storiesOf` e.g. `storiesOf('Components|Paragraph', module)`. This parameter is required.
- `options`(Object) - Available options:
- `include`(Array) - A list of specific story names to create RTL substories of. If this is not provided then all stories will have RTL substories.

## Installation

Expand Down Expand Up @@ -105,12 +111,19 @@ The above example dismisses the use of the `addDecorator` method and decorates t
### buildRTLSubstories
```jsx
// storybook/config.js
import { buildRTLSubstories } from '@bbc/psammead-storybook-helpers';

// create RTL variants of all stories of a kind
buildRTLSubstories('Components|Paragraph');
```
```jsx
import { buildRTLSubstories } from '@bbc/psammead-storybook-helpers';

// must be placed after the storybook configure function
buildRTLSubstories();
// create RTL variants of specific stories of a kind
buildRTLSubstories('Components|Paragraph', {
include: ['containing an inline link'],
});
```
## Contributing
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/utilities/psammead-storybook-helpers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bbc/psammead-storybook-helpers",
"version": "7.0.1",
"version": "8.0.0",
"main": "dist/index.js",
"module": "esm/index.js",
"sideEffects": false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
import { getStorybook, storiesOf } from '@storybook/react';
import withServicesKnob from './withServicesKnob';

export default () => {
getStorybook().forEach(({ kind, stories }) => {
stories.forEach(({ name, render }) => {
storiesOf(`${kind}/RTL`, module)
.addDecorator(withServicesKnob({ defaultService: 'arabic' }))
.add(`RTL - ${name}`, render);
});
const matchesStoryKind = kind => story => story.kind === kind;

const matchesStoryName = name => story => story.name === name;

const buildRTLSubstory = (kind, name, storyFn) => {
const rtlServiceDecorator = withServicesKnob({
defaultService: 'arabic',
services: ['arabic', 'persian', 'urdu', 'pashto'],
});
storiesOf(`${kind}/RTL`, module).add(`RTL - ${name}`, () =>
rtlServiceDecorator(storyFn),
);
};

// eslint-disable-next-line import/prefer-default-export
export const buildRTLSubstories = (storyKind = '', { include = [] } = {}) => {
const allStories = getStorybook();
const { stories } = allStories.find(matchesStoryKind(storyKind));

if (include.length) {
include.forEach(name => {
const { render } = stories.find(matchesStoryName(name));
buildRTLSubstory(storyKind, name, render);
});
} else {
stories.forEach(({ name, render }) =>
buildRTLSubstory(storyKind, name, render),
);
}
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { getStorybook, storiesOf } from '@storybook/react';
import buildRTLSubstories from './buildRTLSubstories';
import { buildRTLSubstories } from './buildRTLSubstories';
import * as withServicesKnob from './withServicesKnob';

const mockAddStory = jest.fn();
const mockAddDecorator = jest.fn(() => ({ add: mockAddStory }));

withServicesKnob.default = jest.fn(() => 'withServicesKnob');

jest.mock('@storybook/react', () => ({
storiesOf: jest.fn(() => ({
addDecorator: mockAddDecorator,
add: mockAddStory,
})),
getStorybook: jest.fn(() => [
{
Expand Down Expand Up @@ -42,34 +41,45 @@ jest.mock('@storybook/react', () => ({
]),
}));

buildRTLSubstories();
afterEach(jest.clearAllMocks);

it('should get all stories', () => {
buildRTLSubstories('Components|Brand');

expect(getStorybook).toHaveBeenCalled();
});

it('should add the withServicesKnob decorator', () => {
it('should add the withServicesKnob decorator so that the default service and service options are configured', () => {
buildRTLSubstories('Components|Brand');

expect(withServicesKnob.default).toHaveBeenCalledWith({
defaultService: 'arabic',
services: ['arabic', 'persian', 'urdu', 'pashto'],
});
expect(mockAddDecorator).toHaveBeenCalledWith('withServicesKnob');
});

it('should create the substories', () => {
it("should build RTL variants of story kind's full suite of stories", () => {
buildRTLSubstories('Components|Brand');

expect(storiesOf.mock.calls[0][0]).toEqual('Components|Brand/RTL');
expect(mockAddStory.mock.calls[0][0]).toEqual('RTL - without brand link');

expect(storiesOf.mock.calls[1][0]).toEqual('Components|Brand/RTL');
expect(mockAddStory.mock.calls[1][0]).toEqual('RTL - with brand link');

expect(storiesOf.mock.calls[2][0]).toEqual('Components|Caption/RTL');
expect(mockAddStory.mock.calls[2][0]).toEqual('RTL - default');
expect(mockAddStory.mock.calls[2]).toBeUndefined();
});

it("should build RTL variants of story kind's specified stories", () => {
buildRTLSubstories('Components|Brand', { include: ['with brand link'] });

expect(storiesOf.mock.calls[0][0]).toEqual('Components|Brand/RTL');
expect(mockAddStory.mock.calls[0][0]).toEqual('RTL - with brand link');

expect(storiesOf.mock.calls[3][0]).toEqual('Components|Caption/RTL');
expect(mockAddStory.mock.calls[3][0]).toEqual('RTL - with offscreen text');
expect(storiesOf.mock.calls[1]).toBeUndefined();
});

expect(storiesOf.mock.calls[4][0]).toEqual('Components|Caption/RTL');
expect(mockAddStory.mock.calls[4][0]).toEqual(
'RTL - containing an inline link',
);
it('should not create RTL substories when no params', () => {
expect(() => buildRTLSubstories()).toThrow();
expect(mockAddStory).not.toHaveBeenCalled();
});
2 changes: 1 addition & 1 deletion packages/utilities/psammead-storybook-helpers/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import withServicesKnob from './withServicesKnob';
import buildRTLSubstories from './buildRTLSubstories';
import { buildRTLSubstories } from './buildRTLSubstories';
import LANGUAGE_VARIANTS from './text-variants';

export { LANGUAGE_VARIANTS, withServicesKnob, buildRTLSubstories };