Home > OS >  Jest throws "Types of property 'id' are incompatible" error when it is trying to
Jest throws "Types of property 'id' are incompatible" error when it is trying to

Time:07-08

So..I am trying to use stories for my unit test with jest RTL to minimize duplication (explained here) and the test throws "Types of property 'id' are incompatible" error when I pass the args that is also used in my story.

I am currently using below packages as my testing suite.

"@storybook/react": "^6.5.9",
"@storybook/testing-react": "^1.2.4",
"@testing-library/react": "^13.3.0",
"jest": "^28.1.1",
// and others...

Below is my test.

import * as React from 'react';
import { screen, render } from '@testing-library/react';

import { Default as Checkbox } from '../../stories/AccountCheckbox.stories';

const renderCheckbox = () => {
  render(<Checkbox {...Checkbox.args} />); // the point where it throws an type error that says 'id is incompatible'.
}

describe('<AccountCheckbox />', () => {
  test('should display account information', () => {
    renderCheckbox();

    expect(screen.getByTestId('example-test-id')).toBeInTheDocument();
  });
});

Below is my story.

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

import AccountCheckbox from '../components/AccountCheckbox';
import { StoryAppWrapper } from '../../.storybook/wrapper/StoryAppWrapper';

export default {
  title: 'AccountCheckbox',
  component: AccountCheckbox,
  decorators: [(Story) => <StoryAppWrapper>{Story()}</StoryAppWrapper>]
} as ComponentMeta<typeof AccountCheckbox>;

const Template: ComponentStory<typeof AccountCheckbox> = (args) => (
  <AccountCheckbox {...args} />
);

export const Default = Template.bind({});

// These are the args I am trying to utilize in my test as well.
Default.args = {
  id: 'example-id',
  testId: 'example-test-id',
  label: 'Account 1',
  selected: false,
  onChange: () => { },
};

Below is the type for the checkbox I declared.

export type CheckboxProps = {
  id: string;
  testId: string;
  label: string;
  selected: boolean;
  onChange: any;
};

Below is the actual code.

import * as React from 'react';
import { Checkbox } from 'custom-lib';

import { CheckboxProps } from '../../types/types';

const AccountCheckbox = ({
  id,
  testId,
  label,
  selected,
  onChange,
}: CheckboxProps): JSX.Element => {
  return (
    <Checkbox
      id={id}
      data-testid={testId}
      label={label}
      state={selected ? 'true' : 'false'}
      onChange={onChange}
    />
  );
};

export default AccountCheckbox;

Can anyone pinpoint what I've missed within these codes?

CodePudding user response:

You're trying to render the Story, not the Checkbox itself. Why not import the checkbox directly, but use the story args too?

import * as React from 'react';
import { screen, render } from '@testing-library/react';
import AccountCheckbox from '../components/AccountCheckbox';
import { Default as AccountCheckboxStory } from '../../stories/AccountCheckbox.stories';

const renderCheckbox = () => {
  render(<AccountCheckbox {...AccountCheckboxStory.args} />);
}

describe('<AccountCheckbox />', () => {
  test('should display account information', () => {
    renderCheckbox();

    expect(screen.getByTestId('example-test-id')).toBeInTheDocument();
  });
});

You may need to adjust paths to the Story/AccountCheckbox as I'm not quite sure what your directory structure looks like.

Update

Going from your comment and the link, it seems that they are using some form of a compositional function to wrap the exported stories and return them as components. So in your case, would you not do this:

import React from 'react';
import { render, screen } from '@testing-library/react';
import { composeStories } from '@storybook/testing-react';

import * as stories from '../../stories/AccountCheckbox.stories';

const { Default: AccountCheckBoxDefault } = composeStories(stories);

test('renders profile page', async () => {
  render(<AccountCheckBoxDefault />);
  // ... some assertions here
});

describe('<AccountCheckbox />', () => {
  test('should display account information', () => {
    renderCheckbox();

    expect(screen.getByTestId('example-test-id')).toBeInTheDocument();
  });
});

I don't think it's actually necessary to pass in the args, as those args should be used by the story itself.

  • Related