test(journey-editor): add reorder tests, fix vacuous isDirty test, fix remove btn name
- Add move-up and move-down tests that verify PUT /items/reorder is called with the swapped ID order; 50ms delay accounts for two await levels before csrfFetch is called (click → handleMoveUp → handleReorder → csrfFetch) - Replace vacuous 'isDirty stays false' test (was asserting a dialog that never renders) with a meaningful publish-button-enabled assertion after adding an item - Update remove button query from 'Wirklich entfernen?' to 'Eintrag entfernen' to match the new journey_remove_item_aria aria-label Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -192,27 +192,92 @@ describe('JourneyEditor — remove with rollback', () => {
|
|||||||
render(JourneyEditor, defaultProps({ geschichte: makeGeschichte({ items }) }));
|
render(JourneyEditor, defaultProps({ geschichte: makeGeschichte({ items }) }));
|
||||||
|
|
||||||
// Click remove (no note → direct remove)
|
// Click remove (no note → direct remove)
|
||||||
await userEvent.click(page.getByRole('button', { name: 'Wirklich entfernen?' }));
|
await userEvent.click(page.getByRole('button', { name: 'Eintrag entfernen' }));
|
||||||
await new Promise((r) => setTimeout(r, 50));
|
await new Promise((r) => setTimeout(r, 50));
|
||||||
|
|
||||||
// Item should be restored after rollback
|
// Item should be restored after rollback
|
||||||
await expect.element(page.getByText('Brief A')).toBeInTheDocument();
|
await expect.element(page.getByText('Brief A')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('item-add does NOT mark dirty (isDirty stays false)', async () => {
|
it('item-add enables publish button (isDirty stays false, canPublish becomes true)', async () => {
|
||||||
const newItem = { id: 'i1', position: 0, note: 'Test' };
|
const newItem = { id: 'i1', position: 0, note: 'Test' };
|
||||||
mockCsrfFetch(() => newItem);
|
mockCsrfFetch(() => newItem);
|
||||||
|
|
||||||
const onSubmit = vi.fn().mockResolvedValue(undefined);
|
render(JourneyEditor, defaultProps());
|
||||||
render(JourneyEditor, defaultProps({ onSubmit }));
|
|
||||||
|
|
||||||
// Add interlude (no unsaved warning should interfere)
|
// Publish should be disabled before adding item
|
||||||
|
await expect.element(page.getByRole('button', { name: /Veröffentlichen/ })).toBeDisabled();
|
||||||
|
|
||||||
|
// Add interlude
|
||||||
await userEvent.click(page.getByText('Zwischentext hinzufügen'));
|
await userEvent.click(page.getByText('Zwischentext hinzufügen'));
|
||||||
await userEvent.fill(page.getByPlaceholder('Zwischentext eingeben…'), 'Test');
|
await userEvent.fill(page.getByPlaceholder('Zwischentext eingeben…'), 'Test');
|
||||||
await userEvent.click(page.getByRole('button', { name: 'Hinzufügen', exact: true }));
|
await userEvent.click(page.getByRole('button', { name: 'Hinzufügen', exact: true }));
|
||||||
|
await new Promise((r) => setTimeout(r, 50));
|
||||||
|
|
||||||
// Saving (which requires non-empty title) — no unsaved warning dialog
|
// After item add, publish becomes enabled — item was added and state is correct
|
||||||
await expect.element(page.getByRole('dialog')).not.toBeInTheDocument();
|
await expect.element(page.getByRole('button', { name: /Veröffentlichen/ })).not.toBeDisabled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('JourneyEditor — reorder via move buttons', () => {
|
||||||
|
it('move-up calls PUT reorder with swapped IDs', async () => {
|
||||||
|
const items = [
|
||||||
|
{ id: 'i1', position: 0, document: docSummary('d1', 'Brief A') },
|
||||||
|
{ id: 'i2', position: 1, document: docSummary('d2', 'Brief B') }
|
||||||
|
];
|
||||||
|
vi.stubGlobal(
|
||||||
|
'fetch',
|
||||||
|
vi.fn().mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: vi.fn().mockResolvedValue([
|
||||||
|
{ id: 'i2', position: 0, document: docSummary('d2', 'Brief B') },
|
||||||
|
{ id: 'i1', position: 1, document: docSummary('d1', 'Brief A') }
|
||||||
|
])
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
render(JourneyEditor, defaultProps({ geschichte: makeGeschichte({ items }) }));
|
||||||
|
|
||||||
|
await userEvent.click(page.getByRole('button', { name: /Brief B.*nach oben verschieben/ }));
|
||||||
|
await new Promise((r) => setTimeout(r, 50)); // handleMoveUp → handleReorder → csrfFetch: two await levels
|
||||||
|
|
||||||
|
expect(globalThis.fetch).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('/items/reorder'),
|
||||||
|
expect.objectContaining({
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({ itemIds: ['i2', 'i1'] })
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('move-down calls PUT reorder with swapped IDs', async () => {
|
||||||
|
const items = [
|
||||||
|
{ id: 'i1', position: 0, document: docSummary('d1', 'Brief A') },
|
||||||
|
{ id: 'i2', position: 1, document: docSummary('d2', 'Brief B') }
|
||||||
|
];
|
||||||
|
vi.stubGlobal(
|
||||||
|
'fetch',
|
||||||
|
vi.fn().mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: vi.fn().mockResolvedValue([
|
||||||
|
{ id: 'i2', position: 0, document: docSummary('d2', 'Brief B') },
|
||||||
|
{ id: 'i1', position: 1, document: docSummary('d1', 'Brief A') }
|
||||||
|
])
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
render(JourneyEditor, defaultProps({ geschichte: makeGeschichte({ items }) }));
|
||||||
|
|
||||||
|
await userEvent.click(page.getByRole('button', { name: /Brief A.*nach unten verschieben/ }));
|
||||||
|
await new Promise((r) => setTimeout(r, 50)); // handleMoveDown → handleReorder → csrfFetch: two await levels
|
||||||
|
|
||||||
|
expect(globalThis.fetch).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('/items/reorder'),
|
||||||
|
expect.objectContaining({
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({ itemIds: ['i2', 'i1'] })
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user