Use this skill when writing or fixing unit tests for React components that use Gamut — prefer setupRtl from @codecademy/gamut-tests, harness patterns for useLogicalProperties and ColorMode, RTL/dir testing, emotion matchers, or removing jest.mock of @codecademy/gamut / gamut-styles.
Scanned 9/11/2026
Install to Claude Code
npx -y skills add Codecademy/gamut --skill gamut-testing --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Gamut Testing?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/codecademy-gamut-testing)More formats (shields.io, HTML) on the badges page.
---
name: gamut-testing
description: Use this skill when writing or fixing unit tests for React components that use Gamut — prefer setupRtl from @codecademy/gamut-tests, harness patterns for useLogicalProperties and ColorMode, RTL/dir testing, emotion matchers, or removing jest.mock of @codecademy/gamut / gamut-styles.
---
# Gamut Testing
Source: `@codecademy/gamut-tests` — `packages/gamut-tests/src/index.tsx`
---
## What `MockGamutProvider` does (under `setupRtl`)
`MockGamutProvider` forwards to `GamutProvider` with:
- `useCache={false}` — stable Emotion output across tests
- `useGlobals={false}` — no global Reboot/Typography bleed between files
- `theme={theme}` — full token theme for styled components
- Optional `useLogicalProperties` — forwarded for logical vs physical CSS in variance
You normally do not import `MockGamutProvider` for plain component tests; `setupRtl` already wraps the component under test once. Import it inside a harness when the SUT needs a non-default provider flag or extra wrappers (see below).
---
## Decision guide
| Scenario | Prefer |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Default unit test for a Gamut (or app) component | `setupRtl(Component, defaultProps)` once per file / describe |
| Vary `useLogicalProperties` across cases | Harness that accepts `useLogicalProperties` and wraps `MockGamutProvider`, then `setupRtl(Harness, defaults)`; pass overrides per `it` / `describe.each` |
| Need `ColorMode` (or other context) around the SUT | Harness with `<ColorMode>` inside the tree, then `setupRtl(Harness)` — no need for raw `render` unless you are testing the provider itself |
| `dir` / RTL behavior (e.g. mirrored layout, `useElementDir`) | Keep using `setupRtl` for the component; set `document.documentElement.setAttribute('dir', 'rtl' \| 'ltr')` (and scroll/viewport stubs if needed) in `beforeEach` / `afterEach`; reset `dir` after tests so suites do not leak |
| Storybook-only mock, chromatic-style wrapper, or non-RTL harness | `MockGamutProvider` (± `ColorMode`) in the exported wrapper component |
---
## `setupRtl` — primary pattern
```tsx
import { setupRtl } from '@codecademy/gamut-tests';
import { MyComponent } from '../MyComponent';
const renderView = setupRtl(MyComponent, {
label: 'Default label',
onClick: jest.fn(),
});
it('renders the label', () => {
const { view } = renderView();
expect(view.getByText('Default label')).toBeInTheDocument();
});
it('accepts prop overrides', () => {
const { view } = renderView({ label: 'Override' });
expect(view.getByText('Override')).toBeInTheDocument();
});
```
`renderView` returns `{ view, props, update }`:
- `view` — RTL `RenderResult` (`getByRole`, `getByLabelText`, `getByText`, …)
- `props` — resolved props (handy for `jest.fn()` assertions)
- `update` — re-render with new props without remounting
### Query and interaction habits (RTL)
- Prefer `getByRole`, `getByLabelText`, and accessible names over CSS selectors or snapshotting class strings unless you are explicitly testing styling.
- Prefer `@testing-library/user-event` over `fireEvent` when simulating real input (import `userEvent` from `@testing-library/user-event` in current major versions).
### Accessing mock functions via `props`
```tsx
import userEvent from '@testing-library/user-event';
it('calls onClick when clicked', async () => {
const { view, props } = renderView();
await userEvent.click(view.getByRole('button'));
expect(props.onClick).toHaveBeenCalled();
});
```
---
## Harness + `setupRtl` when the wrapper is not default
`setupRtl` always wraps with `MockGamutProvider` with default props. To vary `useLogicalProperties`, add `ColorMode`, or compose other providers, define a small harness and pass `setupRtl` that harness — still one `renderView` factory, still `props` / `update` ergonomics.
### Varying `useLogicalProperties` (logical vs physical CSS)
```tsx
import { MockGamutProvider, setupRtl } from '@codecademy/gamut-tests';
import { MyComponent } from '../MyComponent';
type HarnessProps = React.ComponentProps<typeof MyComponent> & {
useLogicalProperties?: boolean;
};
const MyHarness = ({ useLogicalProperties, ...rest }: HarnessProps) => (
<MockGamutProvider useLogicalProperties={useLogicalProperties}>
<MyComponent {...rest} />
</MockGamutProvider>
);
const renderView = setupRtl(MyHarness, { width: '200px' });
describe.each([
{ useLogicalProperties: true as const, widthProp: 'inlineSize' as const },
{ useLogicalProperties: false as const, widthProp: 'width' as const },
])(
'useLogicalProperties=$useLogicalProperties',
({ useLogicalProperties, widthProp }) => {
it(`uses ${widthProp}`, () => {
const { view } = renderView({ useLogicalProperties });
expect(view.getByTestId('my-component-root')).toHaveStyle({
[widthProp]: '200px',
});
});
}
);
```
The outer `setupRtl` wrapper adds a default `MockGamutProvider`; the harness’s inner `MockGamutProvider` sets `useLogicalProperties` for the subtree under test (nested `GamutProvider` / theme is the nearest one Emotion and variance see).
### `ColorMode` without abandoning `setupRtl`
```tsx
import { ColorMode } from '@codecademy/gamut-styles';
import { setupRtl } from '@codecademy/gamut-tests';
const DarkHarness = (props: React.ComponentProps<typeof MyComponent>) => (
<ColorMode mode="dark">
<MyComponent {...props} />
</ColorMode>
);
const renderDark = setupRtl(DarkHarness, { title: 'Hi' });
```
Use `MockGamutProvider` only inside the harness if you also need a non-default Gamut flag and `ColorMode` in the same tree; otherwise `setupRtl(DarkHarness)` is enough.
---
## Raw `render` + `MockGamutProvider` — rare
Reserve `render` from `@testing-library/react` + manual `MockGamutProvider` for cases where a harness would be more obscure than a single inline tree (e.g. highly dynamic one-off trees). If the same wrapper appears more than once, switch to a harness + `setupRtl`.
---
## RTL / `dir` and document-level behavior
Some components (e.g. overlays that call `useElementDir`) resolve direction from `document.documentElement` when there is no real target node. For those tests:
- Set `document.documentElement.setAttribute('dir', 'rtl')` (or `'ltr'`) around the scenario, `unmount` between LTR and RTL assertions when re-rendering, and restore `dir` in `afterEach` so other tests start clean.
- Combine with the harness pattern above when `useLogicalProperties` affects which longhand wins (`left` vs `insetInlineStart`, etc.).
---
## Emotion style assertions
Install `@emotion/jest` matchers if you absolutely need to enable CSS-in-JS assertions:
```tsx
import { matchers } from '@emotion/jest';
expect.extend(matchers);
```
Then assert on styles:
```tsx
expect(element).toHaveStyle({ borderRadius: '2px' });
expect(element).toHaveStyleRule('padding', '1rem');
```
Use `theme` from `@codecademy/gamut-styles` instead of hardcoding token strings:
```tsx
import { theme } from '@codecademy/gamut-styles';
expect(element).toHaveStyle({ columnGap: theme.spacing[40] });
```
---
## Visual test wrappers and Storybook
Exported mocks and stories may wrap with `MockGamutProvider` and `ColorMode` explicitly (no `setupRtl` in Storybook):
```tsx
import { MockGamutProvider } from '@codecademy/gamut-tests';
import { ColorMode } from '@codecademy/gamut-styles';
export const MyComponentMock: React.FC<ComponentProps<typeof MyComponent>> = (
props
) => (
<MockGamutProvider>
<ColorMode mode="light">
<MyComponent {...props} />
</ColorMode>
</MockGamutProvider>
);
```
---
## Common anti-patterns
| Anti-pattern | Fix |
| ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `jest.mock('@codecademy/gamut', () => ({ ... }))` | Remove; use `setupRtl` (or harness + `setupRtl`) |
| `jest.mock('@codecademy/gamut-styles', ...)` | Remove; `MockGamutProvider` / `setupRtl` supplies theme |
| `GamutProvider` in test files | Use `MockGamutProvider` only when building a harness or story; default tests go through `setupRtl` |
| `import { setupRtl } from 'component-test-setup'` in Gamut / apps | Import `setupRtl` from `@codecademy/gamut-tests` so `MockGamutProvider` is applied |
| Repeated `render(<MockGamutProvider>…` | Harness + `setupRtl`, or a shared `renderView` factory |
| One `setupRtl` call per `it` | Define `renderView` once outside `describe`, call it inside each `it` |
| Asserting raw CSS strings for tokens | Use `theme` from `@codecademy/gamut-styles` |
| Leaking `dir="rtl"` between tests | Reset `document.documentElement` in `afterEach` |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!