Skip to content

Commit

Permalink
feat(storybook): from addon-knobs to controls
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Jun 25, 2021
1 parent f77bc78 commit c7adba2
Show file tree
Hide file tree
Showing 38 changed files with 834 additions and 476 deletions.
68 changes: 35 additions & 33 deletions docs/angular/guides/storybook-plugin.md
Expand Up @@ -80,37 +80,43 @@ nx run project-name-e2e:e2e

The url that Cypress points to should look like this:

`'/iframe.html?id=buttoncomponent--primary&knob-text=Click me!&knob-padding&knob-style=default'`
`'/iframe.html?id=buttoncomponent--primary&args=text:Click+me!;padding;style:default'`

- `buttoncomponent` is a lowercase version of the `Title` in the `*.stories.ts` file.
- `primary` is the name of an individual story.
- `knob-style=default` sets the `style` knob to a value of `default`.
- `style=default` sets the `style` control to a value of `default`.

Changing knobs in the url query parameters allows your Cypress tests to test different configurations of your component.
Changing args in the url query parameters allows your Cypress tests to test different configurations of your component. You can [read the documentation](https://storybook.js.org/docs/angular/writing-stories/args#setting-args-through-the-url) for more information.

### Example Files

**\*.component.stories.ts file**

```typescript
import { text, number } from '@storybook/addon-knobs';
import { moduleMetadata, Story, Meta } from '@storybook/angular';
import { ButtonComponent } from './button.component';

export default {
title: 'ButtonComponent',
};

export const primary = () => ({
moduleMetadata: {
imports: [],
},
component: ButtonComponent,
props: {
text: text('text', 'Click me!'),
padding: number('padding', 0),
style: text('style', 'default'),
},
decorators: [
moduleMetadata({
imports: [],
}),
],
} as Meta<ButtonComponent>;

const Template: Story<ButtonComponent> = (args: ButtonComponent) => ({
component: ButtonComponent,
props: args,
});

export const Primary = Template.bind({});
Primary.args = {
text: 'Click me!',
padding: 0,
style: 'default',
};
```

**Cypress \*.spec.ts file**
Expand All @@ -119,7 +125,7 @@ export const primary = () => ({
describe('shared-ui', () => {
beforeEach(() =>
cy.visit(
'/iframe.html?id=buttoncomponent--primary&knob-text=Click me!&knob-padding&knob-style=default'
'/iframe.html?id=buttoncomponent--primary&args=text:Click+me!;padding;style:default'
)
);

Expand All @@ -138,16 +144,14 @@ To register an [addon](https://storybook.js.org/addons/) for all storybook insta
module.exports = {
stories: [...],
...,
addons: [..., '@storybook/addon-knobs/register'],
addons: [..., '@storybook/addon-essentials'],
};
```
2. If a decorator is required, in each project's `<project-path>/.storybook/preview.js` use the `addDecorator` function.
2. If a decorator is required, in each project's `<project-path>/.storybook/preview.js`, you can export an array called `decorators`.

```typescript
import { configure, addDecorator } from '@storybook/angular';
import { withKnobs } from '@storybook/addon-knobs';

addDecorator(withKnobs);
import someDecorator from 'some-storybook-addon';
export const decorators = [someDecorator];
```

**-- OR --**
Expand All @@ -159,16 +163,14 @@ To register an [addon](https://storybook.js.org/addons/) for a single storybook
module.exports = {
stories: [...],
...,
addons: [..., '@storybook/addon-knobs/register'],
addons: [..., '@storybook/addon-essentials'],
};
```
2. If a decorator is required, in `preview.js` use the `addDecorator` function.
2. If a decorator is required, in `preview.js` you can export an array called `decorators`.

```typescript
import { configure, addDecorator } from '@storybook/angular';
import { withKnobs } from '@storybook/addon-knobs';

addDecorator(withKnobs);
import someDecorator from 'some-storybook-addon';
export const decorators = [someDecorator];
```

### More Information
Expand Down Expand Up @@ -290,11 +292,11 @@ If you have not changed the content of the files which the `storybook-configurat
```typescript
module.exports = {
stories: [],
addons: ['@storybook/addon-knobs/register'],
addons: ['@storybook/addon-essentials'],
};
```

- If you have any addons in the `addons.js` file, add them in the `addons` array in the `main.js` file. If you are using the default generated files without any changes, you should only have the `@storybook/addon-knobs/register` addon, which we already put in the array. You can now delete the `addons.js` file.
- If you have any addons in the `addons.js` file, add them in the `addons` array in the `main.js` file. If you are using the default generated files without any changes, you should not have any addons. You can now delete the `addons.js` file.

- The other two files remain unchanged.

Expand Down Expand Up @@ -323,10 +325,10 @@ After you add any addons in the `main.js` file, you can safely delete the `addon
- Rename the file `config.js` to `preview.js` and remove the last line where your stories paths are configured. Now, the contents of the `preview.js` file will look like this:

```typescript
import { addDecorator } from '<%= uiFramework %>';
import { withKnobs } from '@storybook/addon-knobs';
import { addDecorator } from '@storybook/angular';
import { YourDecorator } from '@storybook/<something>';

addDecorator(withKnobs);
addDecorator(YourDecorator);
```

- Modify the contents of `webpack.config.js`. Remove the following lines, which are the TypeScript configuration, which is not needed by Storybook any more:
Expand Down
58 changes: 30 additions & 28 deletions docs/react/guides/storybook-plugin.md
Expand Up @@ -71,28 +71,35 @@ nx run project-name-e2e:e2e

The url that Cypress points to should look like this:

`'/iframe.html?id=buttoncomponent--primary&knob-text=Click me!&knob-padding&knob-style=default'`
`'/iframe.html?id=buttoncomponent--primary&args=text:Click+me!;padding;style:default'`

- `buttoncomponent` is a lowercase version of the `Title` in the `*.stories.ts` file.
- `primary` is the name of an individual story.
- `knob-style=default` sets the `style` knob to a value of `default`.
- `style=default` sets the `style` control to a value of `default`.

Changing knobs in the url query parameters allows your Cypress tests to test different configurations of your component.
Changing args in the url query parameters allows your Cypress tests to test different configurations of your component. You can [read the documentation](https://storybook.js.org/docs/react/writing-stories/args#setting-args-through-the-url) for more information.

### Example Files

**\*.stories.tsx file**

```typescript
import React from 'react';
import { text, number } from '@storybook/addon-knobs';
import { Button } from './button';
import { Story, Meta } from '@storybook/react';
import { Button, ButtonProps } from './button';

export default { title: 'Button' };
export default {
component: Button,
title: 'Button',
} as Meta;

export const primary = () => (
<Button padding={number('Padding', 0)} text={text('Text', 'Click me')} />
);
const Template: Story<ButtonProps> = (args) => <Button {...args} />;

export const Primary = Template.bind({});
Primary.args = {
text: 'Click me!',
padding: 0,
style: 'default',
};
```

**Cypress \*.spec.ts file**
Expand All @@ -101,7 +108,7 @@ export const primary = () => (
describe('shared-ui', () => {
beforeEach(() =>
cy.visit(
'/iframe.html?id=buttoncomponent--primary&knob-text=Click me!&knob-padding&knob-style=default'
'/iframe.html?id=buttoncomponent--primary&args=text:Click+me!;padding;style:default'
)
);

Expand All @@ -120,16 +127,14 @@ To register an [addon](https://storybook.js.org/addons/) for all storybook insta
module.exports = {
stories: [...],
...,
addons: [..., '@storybook/addon-knobs/register'],
addons: [..., '@storybook/addon-essentials'],
};
```
2. If a decorator is required, in each project's `<project-path>/.storybook/preview.js` use the `addDecorator` function.
2. If a decorator is required, in each project's `<project-path>/.storybook/preview.js`, you can export an array called `decorators`.

```typescript
import { configure, addDecorator } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs';

addDecorator(withKnobs);
import someDecorator from 'some-storybook-addon';
export const decorators = [someDecorator];
```

**-- OR --**
Expand All @@ -141,16 +146,14 @@ To register an [addon](https://storybook.js.org/addons/) for a single storybook
module.exports = {
stories: [...],
...,
addons: [..., '@storybook/addon-knobs/register'],
addons: [..., '@storybook/addon-essentials'],
};
```
2. If a decorator is required, in `preview.js` use the `addDecorator` function.
2. If a decorator is required, in `preview.js` you can export an array called `decorators`.

```typescript
import { configure, addDecorator } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs';

addDecorator(withKnobs);
import someDecorator from 'some-storybook-addon';
export const decorators = [someDecorator];
```

### More Information
Expand Down Expand Up @@ -270,11 +273,11 @@ If you have not changed the content of the files which the `storybook-configurat
```typescript
module.exports = {
stories: [],
addons: ['@storybook/addon-knobs/register'],
addons: ['@storybook/addon-essentials'],
};
```

- If you have any addons in the `addons.js` file, add them in the `addons` array in the `main.js` file. If you are using the default generated files without any changes, you should only have the `@storybook/addon-knobs/register` addon, which we already put in the array. You can now delete the `addons.js` file.
- If you have any addons in the `addons.js` file, add them in the `addons` array in the `main.js` file. If you are using the default generated files without any changes, you should not have any addons. You can now delete the `addons.js` file.

- The other two files remain unchanged.

Expand Down Expand Up @@ -303,10 +306,9 @@ After you add any addons in the `main.js` file, you can safely delete the `addon
- Rename the file `config.js` to `preview.js` and remove the last line where your stories paths are configured. Now, the contents of the `preview.js` file will look like this:

```typescript
import { addDecorator } from '<%= uiFramework %>';
import { withKnobs } from '@storybook/addon-knobs';
import { addDecorator } from '@storybook/react';

addDecorator(withKnobs);
addDecorator(<YourDecorator>);
```

- Modify the contents of `webpack.config.js`. Remove the following lines, which are the TypeScript configuration, which is not needed by Storybook any more:
Expand Down
73 changes: 40 additions & 33 deletions e2e/angular/src/storybook.test.ts
Expand Up @@ -35,8 +35,8 @@ describe('Storybook schematics', () => {
`
module.exports = {
stories: [],
addons: ['@storybook/addon-knobs'],
};
addons: ['@storybook/addon-essentials'],
};
console.log('hi there');
`
Expand Down Expand Up @@ -99,22 +99,22 @@ describe('Storybook schematics', () => {
writeFileSync(
tmpProjPath(`libs/${myReactLib}/src/lib/button.stories.tsx`),
`
import React from 'react';
import { Button, ButtonStyle } from './button';
import { text, number } from '@storybook/addon-knobs';
export default { title: 'Button' };
export const primary = () => (
<Button
padding={number('Padding', 0)}
style={text('Style', 'default') as ButtonStyle}
text={text('Text', 'Click me')}
// padding='0'
// style='default'
// text='Click me'
/>
);
import { Story, Meta } from '@storybook/react';
import { Button, ButtonProps } from './button';
export default {
component: Button,
title: 'Button',
} as Meta;
const Template: Story<ButtonProps> = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
text: 'Click me',
padding: 0,
style: 'default',
};
`
);

Expand All @@ -133,14 +133,14 @@ describe('Storybook schematics', () => {
describe('${myAngularLib}', () => {
it('should render the component', () => {
cy.visit('/iframe.html?id=testbuttoncomponent--primary&knob-buttonType=button&knob-style=default&knob-age&knob-isDisabled=false');
cy.visit('/iframe.html?id=testbuttoncomponent--primary&args=buttonType:button;style:default;age;isDisabled:false');
cy.get('proj-test-button').should('exist');
cy.get('button').should('not.be.disabled');
cy.get('button').should('have.class', 'default');
cy.contains('You are 0 years old.');
});
it('should adjust the knobs', () => {
cy.visit('/iframe.html?id=testbuttoncomponent--primary&knob-buttonType=button&knob-style=primary&knob-age=10&knob-isDisabled=true');
it('should adjust the controls', () => {
cy.visit('/iframe.html?id=testbuttoncomponent--primary&args=buttonType:button;style:primary;age:10;isDisabled:true');
cy.get('button').should('be.disabled');
cy.get('button').should('have.class', 'primary');
cy.contains('You are 10 years old.');
Expand All @@ -165,14 +165,14 @@ describe('Storybook schematics', () => {
describe('react-ui', () => {
it('should render the component', () => {
cy.visit(
'/iframe.html?id=button--primary&knob-Style=default&knob-Padding&knob-Text=Click%20me'
'/iframe.html?id=button--primary&args=style:default;padding;text:Click%20me'
);
cy.get('button').should('exist');
cy.get('button').should('have.class', 'default');
});
it('should adjust the knobs', () => {
it('should adjust the controls', () => {
cy.visit(
'/iframe.html?id=button--primary&knob-Style=primary&knob-Padding=10&knob-Text=Other'
'/iframe.html?id=button--primary&args=style:primary;padding:10;text:Other'
);
cy.get('button').should('have.class', 'primary');
});
Expand Down Expand Up @@ -240,21 +240,28 @@ describe('Storybook schematics', () => {
`libs/${angularStorybookLib}/src/lib/myteststory.stories.ts`
),
`
import { moduleMetadata, Story, Meta } from '@storybook/angular';
import { MyTestCmpComponent } from '@${proj}/${anotherTestLib}';
export default {
title: 'My Test Cmp',
component: MyTestCmpComponent,
};
decorators: [
moduleMetadata({
imports: [],
})
],
} as Meta<MyTestCmpComponent>;
const Template: Story<MyTestCmpComponent> = (args: MyTestCmpComponent) => ({
component: MyTestCmpComponent,
props: args,
});
let x = 'hi';
export const primary = () => ({
moduleMetadata: {
imports: [],
},
props: {},
});
export const Primary = Template.bind({});
Primary.args = {
}
`
);

Expand Down Expand Up @@ -289,7 +296,7 @@ export function createTestUILib(libName: string): void {
styleUrls: ['./test-button.component.css']
})
export class TestButtonComponent implements OnInit {
@Input('buttonType') type = 'button';
@Input('buttonType') buttonType = 'button';
@Input() style: ButtonStyle = 'default';
@Input() age!: number;
@Input() isDisabled = false;
Expand Down

0 comments on commit c7adba2

Please sign in to comment.