Test the application Hints about PorscheDesignSystemProvider Additional information when using @testing-library/react Unsupported APIs
CSSStyleSheet.replace(), Intersection Observer, Element.prototype.scrollTo and others.@porsche-design-system/components-react package.setupTest.{js|ts} file.PorscheDesignSystemProvider in order to avoid exceptions.Attention
// setupTest.{js|ts}
import '@porsche-design-system/components-react/jsdom-polyfill';
// SingleComponent.tsx
import { useCallback, useState } from 'react';
import { PTabsBar, type TabsBarUpdateEventDetail } from '@porsche-design-system/components-react/ssr';
export const SingleComponent = (): JSX.Element => {
const [activeTab, setActiveTab] = useState(0);
const onUpdate = useCallback((e: CustomEvent<TabsBarUpdateEventDetail>) => {
setActiveTab(e.detail.activeTabIndex);
}, []);
return (
<>
<PTabsBar activeTabIndex={activeTab} onUpdate={onUpdate} data-testid="host">
<button data-testid="button1">Some label</button>
<button data-testid="button2">Some label</button>
<button data-testid="button3">Some label</button>
</PTabsBar>
<div data-testid="debug">{`Active Tab: ${activeTab + 1}`}</div>
</>
);
};
// SingleComponent.test.tsx
import { PorscheDesignSystemProvider, componentsReady } from '@porsche-design-system/components-react/ssr';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('renders Tabs Bar from Porsche Design System and uses its events', async () => {
const { getByTestId } = render(
<PorscheDesignSystemProvider>
{' '}
{/* required for the component to work */}
<SingleComponent />
</PorscheDesignSystemProvider>
);
await componentsReady(); // we need to make sure Porsche Design System components are initialized
const debug = getByTestId('debug');
const button1 = getByTestId('button1');
const button2 = getByTestId('button2');
const button3 = getByTestId('button3');
expect(debug.innerHTML).toBe('Active Tab: 1');
await userEvent.click(button2);
expect(debug.innerHTML).toBe('Active Tab: 2');
await userEvent.click(button3);
expect(debug.innerHTML).toBe('Active Tab: 3');
await userEvent.click(button1);
expect(debug.innerHTML).toBe('Active Tab: 1');
});
PorscheDesignSystemProvider. Therefore, we offer the
following advice.PorscheDesignSystemProvider
and calls the render function of @testing-library/react:// helper.tsx
import { render, RenderResult } from '@testing-library/react';
import { PorscheDesignSystemProvider } from '@porsche-design-system/components-react/ssr';
export const renderWithProvider = (component: JSX.Element): RenderResult => {
return render(<PorscheDesignSystemProvider>{component}</PorscheDesignSystemProvider>);
};
skipCheckForPorscheDesignSystemProviderDuringTests() that can be used
within your tests. It only takes effect during testing since it relies on process.env.NODE_ENV === 'test'.// setupTest.{js|ts}
import { skipCheckForPorscheDesignSystemProviderDuringTests } from '@porsche-design-system/components-react/ssr';
skipCheckForPorscheDesignSystemProviderDuringTests();
// SomeComponent.test.tsx
import { skipCheckForPorscheDesignSystemProviderDuringTests } from '@porsche-design-system/components-react/ssr';
describe('SomeComponent', () => {
beforeEach(() => {
// either like this
skipCheckForPorscheDesignSystemProviderDuringTests();
});
it('should work', () => {
// or like this
skipCheckForPorscheDesignSystemProviderDuringTests();
// ...
});
});
skipPorscheDesignSystemCDNRequestsDuringTests() that can be used within your tests when
you use the @porsche-design-system/components-react/jsdom-polyfill in your setup. It will suppress all CDN request of
the Porsche Design System.// setupTest.{js|ts}
import { skipPorscheDesignSystemCDNRequestsDuringTests } from '@porsche-design-system/components-react/ssr';
skipPorscheDesignSystemCDNRequestsDuringTests();
// SomeComponent.test.tsx
import { skipPorscheDesignSystemCDNRequestsDuringTests } from '@porsche-design-system/components-react/ssr';
describe('SomeComponent', () => {
beforeEach(() => {
// either like this
skipPorscheDesignSystemCDNRequestsDuringTests();
});
it('should work', () => {
// or like this
skipPorscheDesignSystemCDNRequestsDuringTests();
// ...
});
});
@testing-library/react and jsdom. It is
simply not provided (see Simulate.import { Simulate } from 'react-dom/test-utils';
const button = getByText('SomePorscheDesignSystemButton');
Simulate.submit('button');
getByRole only search light DOM, so they never reach those elements and find nothing.testing sub-package provides a Shadow counterpart for every Testing Library query. These search light
DOM and Shadow DOM, including nested Shadow DOM.getByShadowAltText, getAllByShadowAltText, queryByShadowAltText, queryAllByShadowAltText,
findByShadowAltText, findAllByShadowAltTextgetByShadowDisplayValue, getAllByShadowDisplayValue, queryByShadowDisplayValue,
queryAllByShadowDisplayValue, findByShadowDisplayValue, findAllByShadowDisplayValuegetByShadowLabelText, getAllByShadowLabelText, queryByShadowLabelText,
queryAllByShadowLabelText, findByShadowLabelText, findAllByShadowLabelTextgetByShadowPlaceholderText, getAllByShadowPlaceholderText, queryByShadowPlaceholderText,
queryAllByShadowPlaceholderText, findByShadowPlaceholderText, findAllByShadowPlaceholderTextgetByShadowRole, getAllByShadowRole, queryByShadowRole, queryAllByShadowRole, findByShadowRole,
findAllByShadowRolegetByShadowTestId, getAllByShadowTestId, queryByShadowTestId, queryAllByShadowTestId,
findByShadowTestId, findAllByShadowTestIdgetByShadowText, getAllByShadowText, queryByShadowText, queryAllByShadowText, findByShadowText,
findAllByShadowTextgetByShadowTitle, getAllByShadowTitle, queryByShadowTitle, queryAllByShadowTitle,
findByShadowTitle, findAllByShadowTitleimport { screen } from '@porsche-design-system/components-react/testing';
it('should work for PInputText', async () => {
render(<PInputText label="Some label" name="some-name" />);
await componentsReady();
const input = screen.getByShadowRole('textbox', { name: 'Some label' });
expect(input).toBe(document.querySelector('p-input-text').shadowRoot.querySelector('input'));
});
screen (every query above, bound to document), within, deepQuerySelector, deepQuerySelectorAll,
getAllElementsAndShadowRoots, debug, logShadowDOM, prettyShadowDOM, logRoles, configure and getConfig.Requires a DOM
testing sub-package where no DOM is available throws an error.getByRoleShadowedgetByShadowRolegetByLabelTextShadowedgetByShadowLabelTextgetByTextShadowedgetByShadowTextimport { getByRoleShadowed } from '@porsche-design-system/components-react/testing';
it('should work for PButton', async () => {
render(<PButton>Button</PButton>);
await componentsReady();
expect(getByRoleShadowed('button')).toBeInTheDocument();
});
p-modal, p-flyout, p-sheet, p-drilldownHTMLDialogElement.prototype.show = jest.fn();
HTMLDialogElement.prototype.showModal = jest.fn(function (this: HTMLDialogElement) {
this.setAttribute('open', '');
});
HTMLDialogElement.prototype.close = jest.fn(function (this: HTMLDialogElement) {
this.removeAttribute('open');
});
p-button, p-button-pure, p-checkbox, p-input-date, p-input-email, p-input-month, p-input-number, p-input-password, p-input-search, p-input-tel, p-input-text, p-input-time, p-input-url, p-input-week, p-multi-select, p-pin-code, p-radio-group, p-segmented-control, p-select, p-textareaHTMLElement.prototype.attachInternals = jest.fn(
() =>
({
setFormValue: jest.fn(),
setValidity: jest.fn(),
}) as ElementInternals
);
p-tabs-bar, p-tabs, p-drilldownElement.prototype.animate = vi.fn(
() =>
({
onfinish: null,
cancel: vi.fn(),
finish: vi.fn(),
}) as unknown as Animation
);
