163 lines
4.7 KiB
TypeScript
163 lines
4.7 KiB
TypeScript
import React from 'react';
|
|
import { describe, expect, it, beforeEach, vi } from 'vitest';
|
|
import { render } from '@testing-library/react';
|
|
import PianoRoll from './PianoRoll';
|
|
import { createMockMidiRegion, createMockMidiTrack } from '../../test/utils/mock-data';
|
|
|
|
const pianoRollState = {
|
|
zoom: 1,
|
|
getCurrentSnap: vi.fn(() => 'NO SNAP'),
|
|
getActiveTool: vi.fn(() => 'pointer'),
|
|
getAutomationViewEnabled: vi.fn(() => false),
|
|
getCurrentAutomationType: vi.fn(() => 'pitch-bend'),
|
|
getPianoRollZoom: vi.fn(() => pianoRollState.zoom),
|
|
setPianoRollZoom: vi.fn((zoom: number) => {
|
|
pianoRollState.zoom = zoom;
|
|
}),
|
|
getSheetMusicViewEnabled: vi.fn(() => false),
|
|
getSheetMusicTrackScopeEnabled: vi.fn(() => false),
|
|
getSheetQuantization: vi.fn(() => '16,48'),
|
|
setSheetMusicViewEnabled: vi.fn(),
|
|
setActiveTool: vi.fn(),
|
|
setAutomationViewEnabled: vi.fn(),
|
|
setCurrentAutomationType: vi.fn(),
|
|
setSheetQuantization: vi.fn(),
|
|
setSheetMusicTrackScopeEnabled: vi.fn(),
|
|
setCurrentSnap: vi.fn(),
|
|
setCurrentSuitableChords: vi.fn(),
|
|
setCurrentSuitableChordsPitchClasses: vi.fn(),
|
|
};
|
|
|
|
const mockProject = {
|
|
setPianoRollZoom: vi.fn(),
|
|
};
|
|
|
|
const region = createMockMidiRegion({ id: 'region-1', trackId: '1', trackIndex: 0 });
|
|
const track = createMockMidiTrack({ id: 1, regions: [region] });
|
|
|
|
const storeState = {
|
|
maxBars: 8,
|
|
tracks: [track],
|
|
updateTrack: vi.fn(),
|
|
timeSignature: { numerator: 4, denominator: 4 },
|
|
showChatBox: false,
|
|
showKGOnePanel: false,
|
|
showEventListPanel: false,
|
|
showInstrumentSelection: false,
|
|
keySignature: 'C major',
|
|
selectedMode: 'ionian',
|
|
setSelectedMode: vi.fn(),
|
|
playheadPosition: 0,
|
|
isPlaying: false,
|
|
autoScrollEnabled: false,
|
|
bpm: 120,
|
|
pianoRollScrollRequest: null,
|
|
selectedNoteIds: [],
|
|
automationRedrawVersion: 0,
|
|
};
|
|
|
|
let latestToolbarProps: { zoom: number; onZoomChange: (value: number) => void } | null = null;
|
|
|
|
vi.mock('../../stores/projectStore', () => ({
|
|
useProjectStore: Object.assign(
|
|
(selector?: (state: typeof storeState) => unknown) => selector ? selector(storeState) : storeState,
|
|
{
|
|
getState: () => ({ setAutoScrollEnabled: vi.fn() }),
|
|
setState: vi.fn(),
|
|
}
|
|
),
|
|
}));
|
|
|
|
vi.mock('../../core/state/KGPianoRollState', () => ({
|
|
KGPianoRollState: {
|
|
instance: () => pianoRollState,
|
|
SNAP_OPTIONS: ['NO SNAP'],
|
|
QUANT_POS_OPTIONS: ['1/8'],
|
|
QUANT_LEN_OPTIONS: ['1/8'],
|
|
},
|
|
}));
|
|
|
|
vi.mock('../../core/KGCore', () => ({
|
|
KGCore: {
|
|
FUNCTIONAL_CHORDS_DATA: { ionian: { name: 'Ionian' } },
|
|
instance: () => ({
|
|
getCurrentProject: () => mockProject,
|
|
getSelectedItems: () => [],
|
|
executeCommand: vi.fn(),
|
|
}),
|
|
},
|
|
}));
|
|
|
|
vi.mock('../../core/config/ConfigManager', () => ({
|
|
ConfigManager: {
|
|
instance: () => ({
|
|
getIsInitialized: () => true,
|
|
get: vi.fn(),
|
|
addChangeListener: () => () => undefined,
|
|
}),
|
|
},
|
|
}));
|
|
|
|
vi.mock('../../util/scaleUtil', () => ({
|
|
getSuitableChords: vi.fn(() => ({})),
|
|
noteNameToPitchClass: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('../../util/dialogUtil', () => ({
|
|
showAlert: vi.fn(),
|
|
showPrompt: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('./PianoRollHeader', () => ({ default: () => <div data-testid="header" /> }));
|
|
vi.mock('./NoteAttributeBar', () => ({ default: () => <div data-testid="note-attribute-bar" /> }));
|
|
vi.mock('./PianoRollContent', () => ({ default: () => <div data-testid="content" /> }));
|
|
vi.mock('./PianoRollToolbar', () => ({
|
|
default: (props: { zoom: number; onZoomChange: (value: number) => void }) => {
|
|
latestToolbarProps = props;
|
|
return <div data-testid="toolbar">{props.zoom}x</div>;
|
|
},
|
|
}));
|
|
|
|
describe('PianoRoll zoom persistence', () => {
|
|
beforeEach(() => {
|
|
latestToolbarProps = null;
|
|
pianoRollState.zoom = 1;
|
|
mockProject.setPianoRollZoom.mockReset();
|
|
pianoRollState.getPianoRollZoom.mockClear();
|
|
pianoRollState.setPianoRollZoom.mockClear();
|
|
document.documentElement.style.setProperty('--region-piano-key-width', '60px');
|
|
document.documentElement.style.setProperty('--region-grid-beat-width', '40px');
|
|
});
|
|
|
|
it('restores the previous zoom after closing and reopening the piano roll', () => {
|
|
const firstRender = render(
|
|
<PianoRoll
|
|
onClose={vi.fn()}
|
|
regionId="region-1"
|
|
initialPosition={{ x: 0, y: 0 }}
|
|
initialSize={{ width: 800, height: 400 }}
|
|
/>
|
|
);
|
|
|
|
expect(latestToolbarProps?.zoom).toBe(1);
|
|
|
|
latestToolbarProps?.onZoomChange(3);
|
|
|
|
expect(pianoRollState.setPianoRollZoom).toHaveBeenCalledWith(3);
|
|
expect(mockProject.setPianoRollZoom).toHaveBeenCalledWith(3);
|
|
|
|
firstRender.unmount();
|
|
|
|
render(
|
|
<PianoRoll
|
|
onClose={vi.fn()}
|
|
regionId="region-1"
|
|
initialPosition={{ x: 0, y: 0 }}
|
|
initialSize={{ width: 800, height: 400 }}
|
|
/>
|
|
);
|
|
|
|
expect(latestToolbarProps?.zoom).toBe(3);
|
|
});
|
|
});
|