Skip to content

test: add 120 tests for 24 mixer effect components#1629

Open
ChuxiJ wants to merge 2 commits intomainfrom
feat/mixer-effects-test-coverage
Open

test: add 120 tests for 24 mixer effect components#1629
ChuxiJ wants to merge 2 commits intomainfrom
feat/mixer-effects-test-coverage

Conversation

@ChuxiJ
Copy link
Copy Markdown

@ChuxiJ ChuxiJ commented Apr 8, 2026

Summary

Closes #1628

The mixer effects area was the largest untested UI section in the codebase: 25 effect cards + shared layout components, ~3025 LOC, with only 1 test file (LfoWaveformPreview).

This PR adds 120 new tests across 25 new test files, covering all 24 mixer effect card components plus shared layout utilities.

Coverage Added

  • Dynamics (5 cards, 29 tests): CompressorCard, LimiterCard, GateCard, DeEsserCard, TransientShaperCard
  • EQ (2 cards, 7 tests): EQ3Card, ParametricEQCard
  • Time-based (5 cards, 19 tests): DelayCard, ReverbCard, AlgorithmicReverbCard, ConvolverCard, ChorusCard
  • Modulation (3 cards, 13 tests): FlangerCard, PhaserCard, FilterCard
  • Distortion (2 cards, 10 tests): DistortionCard, SaturationCard
  • Stereo (1 card, 2 tests): StereoImagerCard
  • Spectral (4 cards, 17 tests): SpectralFreezeCard, SpectralBlurCard, SpectralFilterCard, SpectralMorphCard
  • Noise (1 card, 4 tests): NoiseReductionCard
  • Shared (3 components, 17 tests): EffectCardLayout, ParamGroup, ModeButton, effectColors
  • Infrastructure: effectTestHelpers.ts with 22 factory functions for all effect types

Tests Verify

  • All parameter controls render with correct labels
  • Mode selectors (filter type, distortion type, reverb algorithm, etc.) switch correctly
  • Sidechain routing dropdown shows correct tracks and dispatches updates
  • Freeze/Lock toggles update state correctly
  • Visualizations render (mocked canvas components)
  • GR meter animation lifecycle (requestAnimationFrame start/cleanup)
  • LFO controls show/hide based on enabled state
  • effectColors defines valid hex colors for all 23 effect types

Quality Gates

  • 0 TypeScript errors
  • 7140 tests pass (0 regressions, +120 new)
  • Build succeeds

Test plan

  • All 120 new tests pass
  • All 7020 pre-existing tests still pass (0 regressions)
  • TypeScript type check passes (npx tsc --noEmit)
  • Build succeeds

https://claude.ai/code/session_01Q6ZMsrMoPCrnTH8auYHZdd

…t files

The mixer effects area was the largest untested UI section in the codebase:
25 effect cards + shared layout, 3025 LOC, only 1 test file (LfoWaveformPreview).

Coverage added:
- Dynamics: CompressorCard (11), LimiterCard (5), GateCard (5), DeEsserCard (5), TransientShaperCard (3)
- EQ: EQ3Card (3), ParametricEQCard (4)
- Time-based: DelayCard (4), ReverbCard (3), AlgorithmicReverbCard (4), ConvolverCard (5), ChorusCard (4), FlangerCard (3), PhaserCard (3)
- Distortion: DistortionCard (5), SaturationCard (5)
- Stereo: StereoImagerCard (2)
- Spectral: SpectralFreezeCard (5), SpectralBlurCard (2), SpectralFilterCard (4), SpectralMorphCard (6)
- Noise: NoiseReductionCard (4)
- Shared: EffectCardLayout (5), ParamGroup (3), ModeButton (5), effectColors (4), FilterCard (7)
- Test helpers: effectTestHelpers.ts with 22 factory functions

Quality gates: 0 TypeScript errors, 7140 tests pass (0 regressions), build succeeds.

https://claude.ai/code/session_01Q6ZMsrMoPCrnTH8auYHZdd
Copilot AI review requested due to automatic review settings April 8, 2026 21:13
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds broad Vitest + React Testing Library coverage for the Mixer Effects UI, addressing the large previously-untested surface area described in #1628 by introducing per-effect-card rendering/interaction tests plus shared test infrastructure.

Changes:

  • Added new test suites for the majority of mixer effect card components (rendering + basic interactions like mode switches/toggles/selects).
  • Added shared effect factories/helpers to simplify constructing TrackEffect fixtures for tests.
  • Added tests for shared mixer-effects UI utilities (layout + color resolution).

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/components/mixer/effects/tests/AlgorithmicReverbCard.test.tsx Tests rendering + reverb-type switching for AlgorithmicReverbCard
src/components/mixer/effects/tests/ChorusCard.test.tsx Tests ChorusCard controls + visualization presence
src/components/mixer/effects/tests/CompressorCard.test.tsx Tests CompressorCard controls, sidechain selector behavior, and rAF lifecycle
src/components/mixer/effects/tests/ConvolverCard.test.tsx Tests ConvolverCard controls + IR type select updates
src/components/mixer/effects/tests/DeEsserCard.test.tsx Tests DeEsserCard controls, mode switching, and visualization presence
src/components/mixer/effects/tests/DelayCard.test.tsx Tests DelayCard controls, visualization presence, and wet % display
src/components/mixer/effects/tests/DistortionCard.test.tsx Tests DistortionCard controls, type switching, and curve presence
src/components/mixer/effects/tests/EffectCardLayout.test.tsx Tests shared layout components (EffectCardLayout/ParamGroup/ModeButton)
src/components/mixer/effects/tests/effectColors.test.ts Tests EFFECT_COLORS completeness/format and resolveEffectColor output
src/components/mixer/effects/tests/effectTestHelpers.ts Adds shared factories/helpers for constructing effect fixtures and mocks
src/components/mixer/effects/tests/EQ3Card.test.tsx Tests EQ3Card knob/slider labels and displayed frequency values
src/components/mixer/effects/tests/FilterCard.test.tsx Tests FilterCard modes, LFO toggle, and conditional LFO controls
src/components/mixer/effects/tests/FlangerCard.test.tsx Tests FlangerCard controls and presence of mod/LFO preview components
src/components/mixer/effects/tests/GateCard.test.tsx Tests GateCard controls, mode switching, and curve presence
src/components/mixer/effects/tests/LfoWaveformPreview.test.tsx Tests LfoWaveformPreview rendering and animation behavior
src/components/mixer/effects/tests/LimiterCard.test.tsx Tests LimiterCard controls, style switching, and curve presence
src/components/mixer/effects/tests/NoiseReductionCard.test.tsx Tests NoiseReductionCard controls and mode switching
src/components/mixer/effects/tests/ParametricEQCard.test.tsx Tests ParametricEQCard mode switching and simple-mode footer labels
src/components/mixer/effects/tests/PhaserCard.test.tsx Tests PhaserCard controls and modulation display presence
src/components/mixer/effects/tests/ReverbCard.test.tsx Tests ReverbCard controls and curve presence
src/components/mixer/effects/tests/SaturationCard.test.tsx Tests SaturationCard controls, type switching, and curve presence
src/components/mixer/effects/tests/SpectralBlurCard.test.tsx Tests SpectralBlurCard controls
src/components/mixer/effects/tests/SpectralFilterCard.test.tsx Tests SpectralFilterCard controls, point count display, and reset presence
src/components/mixer/effects/tests/SpectralFreezeCard.test.tsx Tests SpectralFreezeCard controls and freeze toggle updates
src/components/mixer/effects/tests/SpectralMorphCard.test.tsx Tests SpectralMorphCard controls, lock toggle updates, and source selector presence
src/components/mixer/effects/tests/StereoImagerCard.test.tsx Tests StereoImagerCard controls and stereo visualization presence
src/components/mixer/effects/tests/TransientShaperCard.test.tsx Tests TransientShaperCard controls and visualization presence

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +34
// ─── Store mock ──────────────────────────────────────────────────────────────

const mockUpdateTrackEffect = vi.fn();
const mockSetSidechainSource = vi.fn();
const mockEnsureAutomationLane = vi.fn();
const mockClearAutomationLane = vi.fn();

const defaultTracks = [
{ id: 'track-1', displayName: 'Kick', clips: [], type: 'audio' as const },
{ id: 'track-2', displayName: 'Snare', clips: [], type: 'audio' as const },
];

export function setupProjectStoreMock(overrides: Record<string, unknown> = {}) {
const mockStore = vi.fn((selector: (s: Record<string, unknown>) => unknown) => {
const state: Record<string, unknown> = {
updateTrackEffect: mockUpdateTrackEffect,
setSidechainSource: mockSetSidechainSource,
ensureAutomationLane: mockEnsureAutomationLane,
clearAutomationLane: mockClearAutomationLane,
project: { tracks: defaultTracks },
...overrides,
};
return selector(state);
});
return { mockStore, mockUpdateTrackEffect, mockSetSidechainSource };
}

Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setupProjectStoreMock is exported but not used anywhere in the repo (the tests still hand-roll vi.mock('../../../../store/projectStore', ...) in each file). This is dead code right now and also keeps mock fns in module scope, which can become a cross-test coupling point if it starts being used. Either switch the effect card tests to use this helper (and expose a reset API), or remove it to avoid confusion.

Suggested change
// ─── Store mock ──────────────────────────────────────────────────────────────
const mockUpdateTrackEffect = vi.fn();
const mockSetSidechainSource = vi.fn();
const mockEnsureAutomationLane = vi.fn();
const mockClearAutomationLane = vi.fn();
const defaultTracks = [
{ id: 'track-1', displayName: 'Kick', clips: [], type: 'audio' as const },
{ id: 'track-2', displayName: 'Snare', clips: [], type: 'audio' as const },
];
export function setupProjectStoreMock(overrides: Record<string, unknown> = {}) {
const mockStore = vi.fn((selector: (s: Record<string, unknown>) => unknown) => {
const state: Record<string, unknown> = {
updateTrackEffect: mockUpdateTrackEffect,
setSidechainSource: mockSetSidechainSource,
ensureAutomationLane: mockEnsureAutomationLane,
clearAutomationLane: mockClearAutomationLane,
project: { tracks: defaultTracks },
...overrides,
};
return selector(state);
});
return { mockStore, mockUpdateTrackEffect, mockSetSidechainSource };
}

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +47
// ─── EffectsEngine mock ──────────────────────────────────────────────────────

export const mockEffectsEngine = {
updateEffectParams: vi.fn(),
getCompressorReduction: vi.fn(() => 0),
getSidechainReduction: vi.fn(() => 0),
getGateReduction: vi.fn(() => 0),
getDeEsserReduction: vi.fn(() => 0),
getLimiterReduction: vi.fn(() => 0),
getSpectralData: vi.fn(() => new Float32Array(128)),
getParametricEQSpectrumData: vi.fn(() => null),
};

Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mockEffectsEngine is exported but not referenced anywhere in the repo (each test file mocks effectsEngine inline instead). Consider either updating the effect tests to reuse this shared mock (and resetting it per test), or deleting it so effectTestHelpers.ts only contains helpers that are actually used.

Suggested change
// ─── EffectsEngine mock ──────────────────────────────────────────────────────
export const mockEffectsEngine = {
updateEffectParams: vi.fn(),
getCompressorReduction: vi.fn(() => 0),
getSidechainReduction: vi.fn(() => 0),
getGateReduction: vi.fn(() => 0),
getDeEsserReduction: vi.fn(() => 0),
getLimiterReduction: vi.fn(() => 0),
getSpectralData: vi.fn(() => new Float32Array(128)),
getParametricEQSpectrumData: vi.fn(() => null),
};

Copilot uses AI. Check for mistakes.

export function makeGateEffect(overrides: Record<string, unknown> = {}) {
return makeEffect('gate', {
threshold: -40, range: -80, attack: 0.5, hold: 10, release: 50,
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makeGateEffect uses attack: 0.5, hold: 10, release: 50, which are wildly out of range relative to the GateCard UI (it multiplies these by 1000 and expects ~0.1–50ms attack, 0–500ms hold, 5–4000ms release). This makes the factory produce unrealistic/default-invalid params and could cause confusing renders or future tests to fail. Update the defaults to match the units expected by GateCard (e.g., values in seconds such as 0.001/0.01/0.05, or whatever the real engine units are).

Suggested change
threshold: -40, range: -80, attack: 0.5, hold: 10, release: 50,
threshold: -40, range: -80, attack: 0.001, hold: 0.01, release: 0.05,

Copilot uses AI. Check for mistakes.
);
// Should just have the children wrapper, no mode/viz/footer wrappers
expect(screen.getByText('Only Children')).toBeDefined();
expect(container.querySelectorAll('[style]').length).toBeGreaterThanOrEqual(1);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "omits sections" assertion is currently ineffective: container.querySelectorAll('[style]') will always be >= 1 because EffectCardLayout always applies an inline style (the stagger animation) to the children wrapper even when mode/visualization/footer are omitted. This test should explicitly assert that the mode/visualization/footer wrappers are absent (e.g., by querying for something unique to those wrappers, or adding stable testids to the layout sections).

Suggested change
expect(container.querySelectorAll('[style]').length).toBeGreaterThanOrEqual(1);
expect(container.firstElementChild).not.toBeNull();
expect(container.firstElementChild?.childElementCount).toBe(1);

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +34
describe('resolveEffectColor', () => {
it('returns fallback hex when document is undefined', () => {
const color = resolveEffectColor('compressor');
expect(color).toBe(EFFECT_COLORS.compressor);
});

Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test description "returns fallback hex when document is undefined" doesn’t match the configured Vitest environment (jsdom), where document is always defined. As written, this test is really asserting the fallback path when the CSS custom property resolves to an empty string. Either stub globalThis.document to undefined for this test, or rename the test to reflect what it’s actually validating.

Copilot uses AI. Check for mistakes.
- Remove unused setupProjectStoreMock and mockEffectsEngine exports
  from effectTestHelpers.ts (dead code, cross-test coupling risk)
- Fix makeGateEffect defaults to use realistic seconds-based values
  (0.001s attack, 0.01s hold, 0.05s release) matching GateCard's
  expected input range
- Fix EffectCardLayout "omits sections" test to assert actual child
  count instead of ineffective style query
- Fix effectColors test description to accurately reflect jsdom
  behavior (CSS custom property empty fallback, not undefined document)

https://claude.ai/code/session_01Q6ZMsrMoPCrnTH8auYHZdd
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.

test: Mixer Effects Test Coverage Sprint — 24 components, 120 new tests

3 participants