Skip to content

meta(refactor-tasks): Add the no-custom-render-helper convention - #125244

Merged
ryan953 merged 2 commits into
masterfrom
ryan953/no-custom-render-helper
Sep 22, 2026
Merged

ryan953 merged 2 commits into
masterfrom
ryan953/no-custom-render-helper

Conversation

@ryan953

@ryan953 ryan953 commented Sep 22, 2026

Copy link
Copy Markdown
Member

Adds a no-custom-render-helper convention to the @sentry/refactor-tasks config, so the daily scan starts reporting test files that hide their JSX behind a local renderFoo() helper, and puts the same guidance in the react-testing skill.

The pattern the rule targets is a helper declared in a spec file whose only job is to forward its arguments into the shared render() / renderGlobalModal() / renderHookWithProviders() helper from sentry-test/reactTestingLibrary. Every file invents its own name and argument shape, so a reader has to go find the helper before any it() block makes sense.

The fix the rule asks for is a component, not an inlined render() call at every call site:

// Before
function renderComponentogprops: LoadingContainerProps = {}) {
  return render(<LoadingContainer {...props}><div>hello!</div></LoadingContainer>);
}

// After
function ExampleLoadingContainer(props: LoadingContainerProps) {
  return <LoadingContainer {...props}><div>hello!</div></LoadingContainer>;
}
// in the test:
const {rerender} = render(<ExampleLoadingContainer isLoading />);

The skill change matters more than the config: the skill is what agents and humans read while writing a test, whereas the scanner config only produces findings after the fact.

Known problem, and why this is a draft

The rule does not work on the scanner's default model. Two -m haiku runs both aborted with a non-JSON reply from the claude-cli backend (Unexpected token 'I', "I already "..., then Unexpected token '<', "<Structure"...), and the run exits 1 while printing a misleading No violations found.. On -m sonnet it returns 58 violations in 82s and exits 0. As a control, no-class-components on the same haiku backend returned 56 violations cleanly, so the backend is healthy and the problem is specific to this rule — most likely its prompt length. The scheduled workflow uses the default model, so this needs sorting before it merges.

What the rule gets wrong today

Running it against master surfaced two gaps worth fixing in the detect text before this lands:

  • The setup-helper exemption is written as "and never call render()", which leaves helpers that do both mock setup and rendering undefined. That is what produced the borderline findings in keyRateLimitsForm, releasesSelectControl, transactionReplays/index and gsAdmin/sentryAppDetails.
  • Helpers that build render() options from their arguments are flagged, but converting them is a regression: resultGrid#renderGrid would repeat a router-config block across 29 call sites. Same for pageFilters/container, onboardingLayout and relocation.

It also produced one clear false positive: spansTable L163-173 is a JSX-returning arrow that never calls render, which the rule already exempts in prose.

Related

The 42 spec files this rule found and that have already been converted are in #125144. That PR is independent of this one and can land first.

No feature flags. No screenshots — this is a scanner config and a skill doc, with no UI surface.

Test files keep growing local renderFoo() helpers that only forward their arguments into the shared render() or renderHookWithProviders() helper. Each file invents its own name and argument shape, so the JSX under test is hidden behind an indirection the reader has to look up first.

The rule asks for an ExampleFoo component instead, so call sites stay in the shape used everywhere else. The react-testing skill gains the same guidance, since that is what agents and humans read while writing a test rather than the scanner config.
…skill

The section was longer than everything around it and carried a full LoadingContainer example. A generic Widget makes the same point in half the space, matching the terse style of the neighbouring rules.
@ryan953
ryan953 merged commit 1dbcd66 into master Sep 22, 2026
62 checks passed
@ryan953
ryan953 deleted the ryan953/no-custom-render-helper branch September 22, 2026 20:52
ryan953 added a commit to getsentry/sentry-docs that referenced this pull request Sep 22, 2026
…erFoo() helper (#19570)

Adds a tip to the "Using React Testing Library" page: render the
component under test, rather than wrapping `render()` in a local
`renderFoo()` helper.

The helper is common in `getsentry/sentry` specs and hides the JSX from
every test that calls it, so a reader has to go find the helper before
an `it()` block makes sense. Each file also invents its own name and
argument shape for the same idea. The tip shows the `ExampleFoo`
component shape we want instead, and sits with the other tips on the
page.

It calls out the part that actually breaks: `rerender` takes an element,
so with a helper the call site no longer controls what is rendered.
Passing a different root component type to `rerender` remounts the tree
and silently drops the state the test was checking. That is not a
hypothetical — converting 42 spec files in getsentry/sentry#125144
surfaced exactly this in two tests.

The tip also names what is **not** this pattern, so it does not read as
a ban on all test helpers: a helper that only registers `MockApiClient`
mocks, or one that takes the element to render as a parameter, is fine
as it is.

## Related

- getsentry/sentry#125144 converts 42 spec files to this shape.
- getsentry/sentry#125244 adds the `no-custom-render-helper` scanner
convention and the matching note in the repo's `react-testing` skill.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants