|
| 1 | +--- |
| 2 | +name: feature-flags |
| 3 | +description: Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React. |
| 4 | +--- |
| 5 | + |
| 6 | +# React Feature Flags |
| 7 | + |
| 8 | +## Flag Files |
| 9 | + |
| 10 | +| File | Purpose | |
| 11 | +|------|---------| |
| 12 | +| `packages/shared/ReactFeatureFlags.js` | Default flags (canary), `__EXPERIMENTAL__` overrides | |
| 13 | +| `packages/shared/forks/ReactFeatureFlags.www.js` | www channel, `__VARIANT__` overrides | |
| 14 | +| `packages/shared/forks/ReactFeatureFlags.native-fb.js` | React Native, `__VARIANT__` overrides | |
| 15 | +| `packages/shared/forks/ReactFeatureFlags.test-renderer.js` | Test renderer | |
| 16 | + |
| 17 | +## Gating Tests |
| 18 | + |
| 19 | +### `@gate` pragma (test-level) |
| 20 | + |
| 21 | +Use when the feature is completely unavailable without the flag: |
| 22 | + |
| 23 | +```javascript |
| 24 | +// @gate enableViewTransition |
| 25 | +it('supports view transitions', () => { |
| 26 | + // This test only runs when enableViewTransition is true |
| 27 | + // and is SKIPPED (not failed) when false |
| 28 | +}); |
| 29 | +``` |
| 30 | + |
| 31 | +### `gate()` inline (assertion-level) |
| 32 | + |
| 33 | +Use when the feature exists but behavior differs based on flag: |
| 34 | + |
| 35 | +```javascript |
| 36 | +it('renders component', async () => { |
| 37 | + await act(() => root.render(<App />)); |
| 38 | + |
| 39 | + if (gate(flags => flags.enableNewBehavior)) { |
| 40 | + expect(container.textContent).toBe('new output'); |
| 41 | + } else { |
| 42 | + expect(container.textContent).toBe('legacy output'); |
| 43 | + } |
| 44 | +}); |
| 45 | +``` |
| 46 | + |
| 47 | +## Adding a New Flag |
| 48 | + |
| 49 | +1. Add to `ReactFeatureFlags.js` with default value |
| 50 | +2. Add to each fork file (`*.www.js`, `*.native-fb.js`, etc.) |
| 51 | +3. If it should vary in www/RN, set to `__VARIANT__` in the fork file |
| 52 | +4. Gate tests with `@gate flagName` or inline `gate()` |
| 53 | + |
| 54 | +## Checking Flag States |
| 55 | + |
| 56 | +Use `/flags` to view states across channels. See the `flags` skill for full command options. |
| 57 | + |
| 58 | +## `__VARIANT__` Flags (GKs) |
| 59 | + |
| 60 | +Flags set to `__VARIANT__` simulate gatekeepers - tested twice (true and false): |
| 61 | + |
| 62 | +```bash |
| 63 | +/test www <pattern> # __VARIANT__ = true |
| 64 | +/test www variant false <pattern> # __VARIANT__ = false |
| 65 | +``` |
| 66 | + |
| 67 | +## Debugging Channel-Specific Failures |
| 68 | + |
| 69 | +1. Run `/flags --diff <channel1> <channel2>` to compare values |
| 70 | +2. Check `@gate` conditions - test may be gated to specific channels |
| 71 | +3. Run `/test <channel> <pattern>` to isolate the failure |
| 72 | +4. Verify flag exists in all fork files if newly added |
| 73 | + |
| 74 | +## Common Mistakes |
| 75 | + |
| 76 | +- **Forgetting both variants** - Always test `www` AND `www variant false` for `__VARIANT__` flags |
| 77 | +- **Using @gate for behavior differences** - Use inline `gate()` if both paths should run |
| 78 | +- **Missing fork files** - New flags must be added to ALL fork files, not just the main one |
| 79 | +- **Wrong gate syntax** - It's `gate(flags => flags.name)`, not `gate('name')` |
0 commit comments