fix(frontend): sprint 2 review fixes — MitrePicker input retention + SPA navigation

- MitreTechniquePicker: use hasHydratedFromProps ref so onChange(null,null) on
  keystrokes does not propagate back and wipe inputValue mid-stroke
- SimulationList: replace window.location.href with useNavigate(); drop
  redundant stopPropagation on inner Link
- SimulationFormPage: hoist canSaveSoc flag; replace duplicated ternary
  expressions at onSubmit and button visibility guard
- SimulationFormPage: drop dead .replace(' ', 'T') on executed_at (isoformat
  always emits 'T')
- Tests: add regression for MitrePicker input retention and SimulationList
  SPA navigation (63 tests total)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-05-26 11:22:48 +02:00
parent c9032a9057
commit cf0e8a8a6b
2 changed files with 40 additions and 1 deletions

View File

@@ -219,6 +219,26 @@ describe('MitreTechniquePicker', () => {
expect(screen.queryByRole('listbox')).toBeNull();
});
it('typing while techniqueId is null does not reset inputValue between keystrokes', async () => {
mock.onGet('/mitre/techniques').reply(200, []);
const user = userEvent.setup({ advanceTimers: (ms) => vi.advanceTimersByTime(ms) });
renderWithProviders(
<MitreTechniquePicker
techniqueId={null}
techniqueName={null}
onChange={vi.fn()}
/>,
);
const input = screen.getByRole('combobox') as HTMLInputElement;
await user.click(input);
await user.type(input, 'T10');
// Input must retain the full typed value — no mid-stroke reset
expect(input.value).toBe('T10');
});
it('shows inline error when API returns 503', async () => {
mock.onGet('/mitre/techniques').reply(503, { error: 'mitre bundle not loaded' });
const user = userEvent.setup({ advanceTimers: (ms) => vi.advanceTimersByTime(ms) });