Loading component...

Published on September 14, 2022Reading time: 8 min read

Add A Mock Component Factory To Storybook

Loading component...

Related Articles

SitecoreAI

Sitecore Workflow Automation with Management API

A practical guide to managing Sitecore workflows programmatically using the Management GraphQL API with production-tested patterns.

November 20, 20251 min read
Blog Card Placeholder
Dev

How to Create a New Sitecore SXA Headless Site

SXA Headless is easy, awesome and powerful! Learn how to create your first Sitecore Headless Tenant & Site with SXA.

November 19, 20251 min read

Loading component...

Digital solutions

Learn how to maximize your investment in Sitecore by working with us.

AI solutions

Dominate your industry. Work with us to digitally transform your business.

Fishtank's proprietary project accelerator. Save time and money. Build what matters.

Utilities

Energy

Education

Healthcare

Manufacturing

Professional services

Financial services

Non-profits and associations

About FishtankThe PlaybookSitecore SnackContact us

Solutions

  • Digital solutions
  • AI solutions
  • TIDAL for XM Cloud

About

  • About Fishtank
  • The Playbook
  • Sitecore Snack
  • Contact us

Insights

Work

Industries

  • Utilities
  • Energy
  • Education
  • Healthcare
  • Manufacturing
  • Professional services
  • Financial services
  • Non-profits and associations

Start typing to search...

If you are having issues with composite components with placeholders in Storybook or Jest, this blog is for you.

Background

In Sitecore Next.js, componentFactory.js is a temp file generated at build time that maps Sitecore renderings to react to components. When you place a rendering into a placeholder, this factory is responsible for correctly finding the right react component to display. However, you may find that if you are trying to display a composite component (with its own custom placeholder) in Storybook, you will be faced with an error:

Component Missing Error Expandable Card

Component Factory Missing Error

This blog is aimed at solving this issue by creating a mock component factory.

The Issue

Storybook is simply unable to find the componentFactory.js because it is missing the Sitecore-specific wrapper that provides context and componentFactory.

My Setup

I have a parent component named ExpandableCardsContainer that contains a placeholder 'expandable-card' and a child component called ExpandableCard meant to be added to the 'expandable-card' placeholder.

  
    const ExpandableCardsContainer = ({ rendering }: ExpandableCardsContainerProps): JSX.Element => {
      return (
        <div className="expandable-cards-container">
          <Placeholder
            name={`expandable-card`}
            rendering={rendering}
          />
        </div>
      );
    };
  
  

    const ExpandableCard = ({ fields }: ExpandableCardProps): JSX.Element => (
      <div className="expandable-card">
        Content
      </div>
    );
  

My Storybook file:


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

    import ExpandableCardsContainer from 'components/Feature/Page Content/ExpandableCardsContainer';
    import { loremIpsumGenerator } from 'lib/lorem-ipsum-generator';
    import { withDatasourceCheckComponentArgs } from 'src/stories/helper';

    export default {
      title: 'Feature/Page Content/ExpandableCardsContainer',
      component: ExpandableCardsContainer,
      argTypes: {},
    } as ComponentMeta<typeof ExpandableCardsContainer>;

    const expandableCardsFactory = (count: number): any => {
      return Array.from(Array(count).keys()).map((index: number) => {
        const imgSrc = `stories/cards/cat${(index % 4) + 1}.jpg`;
        return {
          componentName: 'ExpandableCard',
          dataSource: 'Expandable Card Datasource',
          fields: {
            ... content
          },
        };
      });
    };

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

    export const TenCards = Template.bind({});
    TenCards.args = {
      ...withDatasourceCheckComponentArgs,
      rendering: {
        componentName: 'ExpandableCardsContainer',
        placeholders: {
          'expandable-card': expandableCardsFactory(10),
        },
      },
    };

  

The Solution

Add or merge the code below to your Storybook's preview.js:


    const mockSitecoreContext = {
      context: {
        pageEditing: false,
      },
      setContext: () => { },
    };
    
    export const mockComponentFactory = function (componentName) {
      const components = new Map();
      components.set('YOUR RENDERING NAME', <YOUR COMPONENT>)
    
      const component = components.get(componentName);
    
      if (component?.element) {
        return component.element();
      }
    
      return component?.default || component;
    };
    
    export const decorators = [
      (Story) => (
        <SitecoreContext context={mockSitecoreContext} componentFactory={mockComponentFactory}>
          <Story />
        </SitecoreContext>
      ),
    ];
  

Note that we straight-up copied the structure of the auto-generated componentFactory.js, but we manually set the map from the rendering name to their respective components. In my case, I had to add 'components.set('ExpandableCard', ExpandableCard)'. Do not forget to import the component FYI.

Additionally, if you have not, I included the mockSitecoreContext in order to bypass 'missing sitecore Context' error.

Boom.

Working Component

Solutions

  • Digital solutions
  • AI solutions

Brands

  • TIDAL for SitecoreAI
  • Sitecore Snack
  • The Playbook

Fishtank lore

  • Work
  • Insights
  • About us
  • Contact us

Industries

Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing
Utilities
Professional services
Energy
Financial services
Healthcare
Education
Non-profits and associations
Manufacturing

2025 @All Rights Reserved. Privacy Policy.

FISHTANK