Antoine Deloy
Antoine Deloy

Reputation: 85

React Storybook passing functions in args

I currently struggle to finish a story in React story for one of my components : (images below)

My component receives a props from a parent, a boolean and a function to modify this boolean. When I click on a button it should change the value of this boolean (false to true or true to false). I can't seem to test this behaviour on storybook. I don't know if I do things the right way, but it seems impossible to pass a function from my .Stories filecode to my component to test it.

My question is : Am i doing things the right way and is storybook built for this kind of test ?

story file code :

import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { ModelCard } from './';

export default {
  title: 'ModelCard',
  component: ModelCard,
  argTypes: {
    yearProduct: { control : 'text'},
    ecoDesigned: { control: 'boolean'},
    titleProduct: {control: 'text'},
    photoProduct: {control: 'text'},
    setEcoDesigned: {action: 'clicked'}
  }
} as ComponentMeta<typeof ModelCard>;

const Template: ComponentStory<typeof ModelCard> = (args) => <ModelCard {...args}/>;
export const ModelCardCompleteControls = Template.bind({});
ModelCardCompleteControls.args = {
  yearProduct: '2018',
  ecoDesigned: false,
  titleProduct: '66180 - W200 S | 1019507 - ATHLLE Watches or Stopwatche 7026 2021 | GEDS',
  photoProduct: 'https://picsum.photos/200',
};

My component code :

import React from 'react';
import { useState } from 'react';
import { VtmnButton, VtmnIcon } from '@vtmn/react';
import { EcoDesignedDot } from './EcoDesignedDot';

import './modelcard.scss';

interface ModelCardProps {
    photoProduct: string;
    yearProduct: string,
    titleProduct: string,
    ecoDesigned: boolean;
    setEcoDesigned: (ecoDesigned: boolean) => void;
}

export const ModelCard = ({ yearProduct, titleProduct, photoProduct, ecoDesigned, setEcoDesigned }: ModelCardProps) => {
  
  const [open, setOpen] = useState(false);
  
  return (
    <article className="model-card">
      <section className="vtmn-grid vtmn-grid-cols-12 vtmn-items-center vtmn-space-y-5">
        <p className="vtmn-col-span-1">{yearProduct}</p>
        <img className="vtmn-col-span-1"
          style={{ borderRadius: 5 }}
          src={photoProduct} width={60}
          height={60} />
        <p className="vtmn-col-span-6">{titleProduct}</p>
        <div className="vtmn-col-span-3">
          <EcoDesignedDot ecoDesigned={ecoDesigned}/>
        </div>
        <div className="vtmn-col-span-1" onClick={() => setOpen(!open)}>
          <VtmnIcon value="arrow-up-s-line" className={open ? 'reversed_angle' : 'original_angle'} />
        </div>
      </section>
      <section className="vtmn-grid vtmn-grid-cols-12">
        {
          open && <div className="vtmn-col-start-3 vtmn-col-span-5">
            <p>
              Votre produit est-il éco-design ?
            </p>
            <VtmnButton onClick={() => setEcoDesigned(true)} variant={ecoDesigned ? 'primary' : 'secondary'} size="medium">Oui</VtmnButton> // This is what I'm talking about
            <VtmnButton onClick={() => setEcoDesigned(false)} variant={ecoDesigned ? 'secondary' : 'primary'} size="medium">Non</VtmnButton> // This is what I'm talking about
          </div>
        }
      </section>
    </article>
  );
};

Upvotes: 5

Views: 24462

Answers (1)

Ramesh Reddy
Ramesh Reddy

Reputation: 10662

You can add useState in the Template function because it's a react component but, make sure that you send these values to the ModelCard component properly.

const Template: ComponentStory<typeof ModelCard> = (args) => {

    const [ecoDesigned, setEcoDesigned] = useState(false);

    return <ModelCard {...args} ecoDesigned={ecoDesigned} setEcoDesigned={setEcoDesigned}/>;
};

The args object will have all the default props. So, you should make sure that these are overwritten.

Upvotes: 11

Related Questions