mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-13 19:33:46 +00:00
fix: insert above shortcut (#1020)
refactor: unify setCursor and useEventSelection
This commit is contained in:
committed by
GitHub
parent
c2039866b4
commit
8b3abe9d61
@@ -19,13 +19,10 @@ function persistModeToSession(mode: AppMode) {
|
||||
type AppModeStore = {
|
||||
mode: AppMode;
|
||||
setMode: (mode: AppMode) => void;
|
||||
cursor: string | null;
|
||||
setCursor: (cursor: string | null) => void;
|
||||
};
|
||||
|
||||
export const useAppMode = create<AppModeStore>()((set) => ({
|
||||
mode: getModeFromSession(),
|
||||
cursor: null,
|
||||
setMode: (mode: AppMode) => {
|
||||
persistModeToSession(mode);
|
||||
|
||||
@@ -33,5 +30,4 @@ export const useAppMode = create<AppModeStore>()((set) => ({
|
||||
return { mode };
|
||||
});
|
||||
},
|
||||
setCursor: (cursor: string | null) => set({ cursor }),
|
||||
}));
|
||||
|
||||
@@ -14,6 +14,7 @@ import { cloneEvent } from '../../common/utils/eventsManager';
|
||||
|
||||
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
||||
import RundownEmpty from './RundownEmpty';
|
||||
import { useEventSelection } from './useEventSelection';
|
||||
|
||||
import style from './Rundown.module.scss';
|
||||
|
||||
@@ -33,7 +34,9 @@ export default function Rundown({ data }: RundownProps) {
|
||||
const { entryCopyId, setEntryCopyId } = useEntryCopy();
|
||||
|
||||
// cursor
|
||||
const { cursor, mode: appMode, setCursor } = useAppMode();
|
||||
const { mode: appMode } = useAppMode();
|
||||
const { clearSelectedEvents, setSelectedEvents, cursor } = useEventSelection();
|
||||
|
||||
const cursorRef = useRef<HTMLDivElement | null>(null);
|
||||
const scrollRef = useRef<HTMLDivElement | null>(null);
|
||||
useFollowComponent({ followRef: cursorRef, scrollRef, doFollow: appMode === AppMode.Run });
|
||||
@@ -44,34 +47,42 @@ export default function Rundown({ data }: RundownProps) {
|
||||
const deleteAtCursor = useCallback(
|
||||
(cursor: string | null) => {
|
||||
if (!cursor) return;
|
||||
const previous = getPreviousNormal(rundown, order, cursor).entry?.id ?? null;
|
||||
const { entry, index } = getPreviousNormal(rundown, order, cursor);
|
||||
deleteEvent([cursor]);
|
||||
setCursor(previous);
|
||||
if (entry && index !== null) {
|
||||
setSelectedEvents({ id: entry.id, selectMode: 'click', index });
|
||||
}
|
||||
},
|
||||
[deleteEvent, order, rundown, setCursor],
|
||||
[rundown, order, deleteEvent, setSelectedEvents],
|
||||
);
|
||||
|
||||
const insertAtCursor = useCallback(
|
||||
(type: SupportedEvent | 'clone', cursor: string | null, above = false) => {
|
||||
const adjustedCursor = above ? getPreviousNormal(rundown, order, cursor ?? '').entry?.id ?? null : cursor;
|
||||
|
||||
if (adjustedCursor === null) {
|
||||
const insertCopyAtId = useCallback(
|
||||
(atId: string | null, copyId: string | null, above = false) => {
|
||||
const adjustedCursor = above ? getPreviousNormal(rundown, order, atId ?? '').entry?.id ?? null : atId;
|
||||
if (copyId === null) {
|
||||
// we cant clone without selection
|
||||
if (type === 'clone') {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const cloneEntry = rundown[copyId];
|
||||
if (cloneEntry?.type === SupportedEvent.Event) {
|
||||
//if we don't have a cursor add the new event on top
|
||||
const newEvent = cloneEvent(cloneEntry, adjustedCursor ?? undefined);
|
||||
addEvent(newEvent);
|
||||
}
|
||||
},
|
||||
[addEvent, order, rundown],
|
||||
);
|
||||
|
||||
const insertAtId = useCallback(
|
||||
(type: SupportedEvent, id: string | null, above = false) => {
|
||||
const adjustedCursor = above ? getPreviousNormal(rundown, order, id ?? '').entry?.id ?? null : id;
|
||||
if (adjustedCursor === null) {
|
||||
// the only thing to do is adding an event at top
|
||||
addEvent({ type });
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'clone') {
|
||||
const cursorEvent = rundown[adjustedCursor];
|
||||
if (cursorEvent?.type === SupportedEvent.Event) {
|
||||
const newEvent = cloneEvent(cursorEvent, cursorEvent.id);
|
||||
addEvent(newEvent);
|
||||
}
|
||||
} else if (type === SupportedEvent.Event) {
|
||||
if (type === SupportedEvent.Event) {
|
||||
const newEvent = {
|
||||
type: SupportedEvent.Event,
|
||||
};
|
||||
@@ -92,23 +103,26 @@ export default function Rundown({ data }: RundownProps) {
|
||||
if (order.length < 1) {
|
||||
return;
|
||||
}
|
||||
let newCursor: string | undefined;
|
||||
let newCursor: string | null;
|
||||
let newIndex: number | null;
|
||||
if (cursor === null) {
|
||||
// there is no cursor, we select the first or last depending on direction if it exists
|
||||
newCursor = direction === 'up' ? getLastNormal(rundown, order)?.id : getFirstNormal(rundown, order)?.id;
|
||||
newCursor =
|
||||
(direction === 'up' ? getLastNormal(rundown, order)?.id : getFirstNormal(rundown, order)?.id) ?? null;
|
||||
newIndex = direction === 'up' ? order.length : 0;
|
||||
} else {
|
||||
// otherwise we select the next or previous
|
||||
newCursor =
|
||||
direction === 'up'
|
||||
? getPreviousNormal(rundown, order, cursor).entry?.id
|
||||
: getNextNormal(rundown, order, cursor).entry?.id;
|
||||
const selected =
|
||||
direction === 'up' ? getPreviousNormal(rundown, order, cursor) : getNextNormal(rundown, order, cursor);
|
||||
newCursor = selected.entry?.id ?? null;
|
||||
newIndex = selected.index;
|
||||
}
|
||||
|
||||
if (newCursor) {
|
||||
setCursor(newCursor);
|
||||
if (newCursor && newIndex !== null) {
|
||||
setSelectedEvents({ id: newCursor, selectMode: 'click', index: newIndex });
|
||||
}
|
||||
},
|
||||
[order, rundown, setCursor],
|
||||
[order, rundown, setSelectedEvents],
|
||||
);
|
||||
|
||||
const moveEntry = useCallback(
|
||||
@@ -134,22 +148,22 @@ export default function Rundown({ data }: RundownProps) {
|
||||
['alt + mod + ArrowDown', () => moveEntry(cursor, 'down'), { preventDefault: true }],
|
||||
['alt + mod + ArrowUp', () => moveEntry(cursor, 'up'), { preventDefault: true }],
|
||||
|
||||
['Escape', () => setCursor(null), { preventDefault: true }],
|
||||
['Escape', () => clearSelectedEvents(), { preventDefault: true }],
|
||||
|
||||
['mod + Backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
||||
|
||||
['alt + E', () => insertAtCursor(SupportedEvent.Event, cursor), { preventDefault: true }],
|
||||
['alt + shift + E', () => insertAtCursor(SupportedEvent.Event, cursor, true), { preventDefault: true }],
|
||||
['alt + E', () => insertAtId(SupportedEvent.Event, cursor), { preventDefault: true }],
|
||||
['alt + shift + E', () => insertAtId(SupportedEvent.Event, cursor, true), { preventDefault: true }],
|
||||
|
||||
['alt + B', () => insertAtCursor(SupportedEvent.Block, cursor), { preventDefault: true }],
|
||||
['alt + shift + B', () => insertAtCursor(SupportedEvent.Block, cursor, true), { preventDefault: true }],
|
||||
['alt + B', () => insertAtId(SupportedEvent.Block, cursor), { preventDefault: true }],
|
||||
['alt + shift + B', () => insertAtId(SupportedEvent.Block, cursor, true), { preventDefault: true }],
|
||||
|
||||
['alt + D', () => insertAtCursor(SupportedEvent.Delay, cursor), { preventDefault: true }],
|
||||
['alt + shift + D', () => insertAtCursor(SupportedEvent.Delay, cursor, true), { preventDefault: true }],
|
||||
['alt + D', () => insertAtId(SupportedEvent.Delay, cursor), { preventDefault: true }],
|
||||
['alt + shift + D', () => insertAtId(SupportedEvent.Delay, cursor, true), { preventDefault: true }],
|
||||
|
||||
['mod + C', () => setEntryCopyId(cursor), { preventDefault: true }],
|
||||
['mod + V', () => insertAtCursor('clone', entryCopyId), { preventDefault: true }],
|
||||
['mod + shift + V', () => insertAtCursor('clone', entryCopyId, true), { preventDefault: true }],
|
||||
['mod + V', () => insertCopyAtId(cursor, entryCopyId), { preventDefault: true }],
|
||||
['mod + shift + V', () => insertCopyAtId(cursor, entryCopyId, true), { preventDefault: true }],
|
||||
|
||||
['alt + backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
||||
]);
|
||||
@@ -165,8 +179,9 @@ export default function Rundown({ data }: RundownProps) {
|
||||
if (appMode !== AppMode.Run || !featureData?.selectedEventId) {
|
||||
return;
|
||||
}
|
||||
setCursor(featureData.selectedEventId);
|
||||
}, [appMode, featureData.selectedEventId, setCursor]);
|
||||
const index = order.findIndex((id) => id === featureData.selectedEventId);
|
||||
setSelectedEvents({ id: featureData.selectedEventId, selectMode: 'click', index });
|
||||
}, [appMode, featureData.selectedEventId, order, setSelectedEvents]);
|
||||
|
||||
const handleOnDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
@@ -185,7 +200,7 @@ export default function Rundown({ data }: RundownProps) {
|
||||
};
|
||||
|
||||
if (statefulEntries.length < 1) {
|
||||
return <RundownEmpty handleAddNew={() => insertAtCursor(SupportedEvent.Event, null)} />;
|
||||
return <RundownEmpty handleAddNew={() => insertAtId(SupportedEvent.Event, cursor)} />;
|
||||
}
|
||||
|
||||
let previousStart: MaybeNumber = null;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { MaybeNumber, OntimeEvent, OntimeRundownEntry, Playback, SupportedEvent
|
||||
|
||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||
import useMemoisedFn from '../../common/hooks/useMemoisedFn';
|
||||
import { useAppMode } from '../../common/stores/appModeStore';
|
||||
import { useEmitLog } from '../../common/stores/logger';
|
||||
import { cloneEvent } from '../../common/utils/eventsManager';
|
||||
|
||||
@@ -56,22 +55,15 @@ export default function RundownEntry(props: RundownEntryProps) {
|
||||
} = props;
|
||||
const { emitError } = useEmitLog();
|
||||
const { addEvent, updateEvent, batchUpdateEvents, deleteEvent, swapEvents } = useEventAction();
|
||||
const cursor = useAppMode((state) => state.cursor);
|
||||
const setCursor = useAppMode((state) => state.setCursor);
|
||||
const { selectedEvents, unselect, clearSelectedEvents } = useEventSelection();
|
||||
|
||||
const removeOpenEvent = useCallback(() => {
|
||||
unselect(data.id);
|
||||
// clear cursor if we are deleting the event that is currently selected
|
||||
if (cursor === data.id) {
|
||||
setCursor(null);
|
||||
}
|
||||
}, [unselect, data.id, cursor, setCursor]);
|
||||
}, [unselect, data.id]);
|
||||
|
||||
const clearMultiSelection = useCallback(() => {
|
||||
clearSelectedEvents();
|
||||
setCursor(null);
|
||||
}, [clearSelectedEvents, setCursor]);
|
||||
}, [clearSelectedEvents]);
|
||||
|
||||
// Create / delete new events
|
||||
type FieldValue = {
|
||||
|
||||
@@ -11,7 +11,6 @@ import { IoTrash } from '@react-icons/all-files/io5/IoTrash';
|
||||
import { EndAction, MaybeNumber, MaybeString, OntimeEvent, Playback, TimerType, TimeStrategy } from 'ontime-types';
|
||||
|
||||
import { useContextMenu } from '../../../common/hooks/useContextMenu';
|
||||
import { useAppMode } from '../../../common/stores/appModeStore';
|
||||
import { cx, getAccessibleColour } from '../../../common/utils/styleUtils';
|
||||
import type { EventItemActions } from '../RundownEntry';
|
||||
import { useEventIdSwapping } from '../useEventIdSwapping';
|
||||
@@ -88,7 +87,6 @@ export default function EventBlock(props: EventBlockProps) {
|
||||
} = props;
|
||||
const { selectedEventId, setSelectedEventId, clearSelectedEventId } = useEventIdSwapping();
|
||||
const { selectedEvents, setSelectedEvents } = useEventSelection();
|
||||
const setCursor = useAppMode((state) => state.setCursor);
|
||||
const handleRef = useRef<null | HTMLSpanElement>(null);
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
@@ -231,7 +229,6 @@ export default function EventBlock(props: EventBlockProps) {
|
||||
const index = eventIndex - 1;
|
||||
const editMode = getSelectionMode(event);
|
||||
setSelectedEvents({ id: eventId, index, selectMode: editMode });
|
||||
setCursor(eventId);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -17,7 +17,6 @@ import { useEventSelection } from '../useEventSelection';
|
||||
|
||||
export default function RundownMenu() {
|
||||
const clearSelectedEvents = useEventSelection((state) => state.clearSelectedEvents);
|
||||
const setCursor = useAppMode((state) => state.setCursor);
|
||||
const appMode = useAppMode((state) => state.mode);
|
||||
const { deleteAllEvents } = useEventAction();
|
||||
|
||||
@@ -27,9 +26,8 @@ export default function RundownMenu() {
|
||||
const deleteAll = useCallback(() => {
|
||||
deleteAllEvents();
|
||||
clearSelectedEvents();
|
||||
setCursor(null);
|
||||
onClose();
|
||||
}, [clearSelectedEvents, deleteAllEvents, onClose, setCursor]);
|
||||
}, [clearSelectedEvents, deleteAllEvents, onClose]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MouseEvent } from 'react';
|
||||
import { isOntimeEvent, OntimeEvent, RundownCached } from 'ontime-types';
|
||||
import { isOntimeEvent, MaybeNumber, MaybeString, OntimeEvent, RundownCached } from 'ontime-types';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { RUNDOWN } from '../../common/api/constants';
|
||||
@@ -10,7 +10,8 @@ export type SelectionMode = 'shift' | 'click' | 'ctrl';
|
||||
|
||||
interface EventSelectionStore {
|
||||
selectedEvents: Set<string>;
|
||||
anchoredIndex: number | null;
|
||||
anchoredIndex: MaybeNumber;
|
||||
cursor: MaybeString;
|
||||
setSelectedEvents: (selectionArgs: { id: string; index: number; selectMode: SelectionMode }) => void;
|
||||
clearSelectedEvents: () => void;
|
||||
clearMultiSelect: () => void;
|
||||
@@ -20,13 +21,14 @@ interface EventSelectionStore {
|
||||
export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
||||
selectedEvents: new Set(),
|
||||
anchoredIndex: null,
|
||||
cursor: null,
|
||||
setSelectedEvents: (selectionArgs) => {
|
||||
const { id, index, selectMode } = selectionArgs;
|
||||
const { selectedEvents, anchoredIndex } = get();
|
||||
|
||||
// on click, we replace selection with event
|
||||
if (selectMode === 'click') {
|
||||
return set({ selectedEvents: new Set([id]), anchoredIndex: index });
|
||||
return set({ selectedEvents: new Set([id]), anchoredIndex: index, cursor: id });
|
||||
}
|
||||
|
||||
// on ctrl + click, we toggle the selection of that event
|
||||
@@ -39,6 +41,7 @@ export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
||||
return set({
|
||||
selectedEvents: selectedEvents.add(id),
|
||||
anchoredIndex: index,
|
||||
cursor: id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,7 +86,7 @@ export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
||||
});
|
||||
}
|
||||
},
|
||||
clearSelectedEvents: () => set({ selectedEvents: new Set(), anchoredIndex: null }),
|
||||
clearSelectedEvents: () => set({ selectedEvents: new Set(), anchoredIndex: null, cursor: null }),
|
||||
clearMultiSelect: () => {
|
||||
const { selectedEvents } = get();
|
||||
const [firstSelected] = selectedEvents;
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('Copy Past', async ({ page }) => {
|
||||
await page.goto('http://localhost:4001/rundown');
|
||||
|
||||
// clear rundown
|
||||
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||
|
||||
//create event
|
||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||
await page.getByTestId('entry-1').click();
|
||||
await page.getByLabel('Cue', { exact: true }).click();
|
||||
await page.getByLabel('Cue', { exact: true }).fill('4');
|
||||
await page.getByLabel('Cue', { exact: true }).press('Enter');
|
||||
await page.getByTestId('entry-1').click();
|
||||
await page.getByTestId('block__title').click();
|
||||
await page.getByTestId('block__title').fill('test');
|
||||
await page.getByTestId('block__title').press('Enter');
|
||||
|
||||
//copy past below
|
||||
await page.locator('div').filter({ hasText: /^4$/ }).click();
|
||||
await page.locator('div').filter({ hasText: /^4$/ }).press('Control+c');
|
||||
await page.locator('div').filter({ hasText: /^4$/ }).press('Control+v');
|
||||
|
||||
//assert
|
||||
await expect(page.getByTestId('entry-2')).toBeVisible();
|
||||
await expect(page.getByTestId('entry-2').getByTestId('block__title')).toHaveValue('test');
|
||||
await expect(page.getByTestId('entry-2').locator('#event-block')).toContainText('5');
|
||||
|
||||
//copy past above
|
||||
await page.locator('div').filter({ hasText: /^5$/ }).click();
|
||||
await page.locator('div').filter({ hasText: /^5$/ }).press('Control+c');
|
||||
await page.locator('div').filter({ hasText: /^5$/ }).press('Control+Shift+v');
|
||||
|
||||
//assert
|
||||
await expect(page.getByTestId('entry-2')).toBeVisible();
|
||||
await expect(page.getByTestId('entry-2').getByTestId('block__title')).toHaveValue('test');
|
||||
await expect(page.getByTestId('entry-2').locator('#event-block')).toContainText('4.1');
|
||||
});
|
||||
|
||||
test('Move', async ({ page }) => {
|
||||
await page.goto('http://localhost:4001/rundown');
|
||||
|
||||
// clear rundown
|
||||
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||
|
||||
//create events
|
||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||
await page.getByRole('button', { name: 'Event' }).nth(4).click();
|
||||
await page.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
||||
|
||||
//copy move down
|
||||
await page.getByTestId('entry-1').locator('#event-block').getByText('1').click();
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Control+ArrowDown');
|
||||
await expect(page.getByTestId('entry-2').locator('#event-block')).toContainText('1');
|
||||
|
||||
//copy move up
|
||||
await page.getByTestId('entry-3').locator('#event-block').getByText('3').click();
|
||||
await page.getByTestId('entry-3').locator('#event-block div').filter({ hasText: '3' }).press('Alt+Control+ArrowUp');
|
||||
await page.getByTestId('entry-2').locator('div').filter({ hasText: /^3$/ }).press('Alt+Control+ArrowUp');
|
||||
await expect(page.getByTestId('entry-1').locator('#event-block')).toContainText('3');
|
||||
});
|
||||
|
||||
test('Add block', async ({ page }) => {
|
||||
await page.goto('http://localhost:4001/rundown');
|
||||
|
||||
// clear rundown
|
||||
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||
|
||||
//create events
|
||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||
await page.getByTestId('entry-1').click();
|
||||
await page.getByTestId('block__title').press('Escape');
|
||||
|
||||
//add block below
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+B');
|
||||
await expect(page.getByPlaceholder('Block title')).toBeVisible();
|
||||
|
||||
//add block above
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Shift+B');
|
||||
await expect(page.getByTestId('entry-0').getByTestId('block__title')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Add delay', async ({ page }) => {
|
||||
await page.goto('http://localhost:4001/rundown');
|
||||
|
||||
// clear rundown
|
||||
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||
|
||||
//create events
|
||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||
await page.getByTestId('entry-1').click();
|
||||
await page.getByTestId('block__title').press('Escape');
|
||||
|
||||
//add delay below
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+D');
|
||||
await expect(page.getByTestId('delay-input')).toBeVisible();
|
||||
|
||||
//add delay above
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Shift+D');
|
||||
await expect(page.getByTestId('entry-0').getByTestId('delay-input')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Add event', async ({ page }) => {
|
||||
await page.goto('http://localhost:4001/rundown');
|
||||
|
||||
// clear rundown
|
||||
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||
|
||||
//create events
|
||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||
await page.getByTestId('entry-1').click();
|
||||
await page.getByTestId('block__title').press('Escape');
|
||||
|
||||
//add event below
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+E');
|
||||
await expect(page.getByTestId('entry-2').locator('#event-block').getByText('2')).toBeVisible();
|
||||
|
||||
//add event above
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Shift+E');
|
||||
await expect(page.getByTestId('entry-1').locator('#event-block')).toContainText('0.1');
|
||||
});
|
||||
|
||||
test('Delete event', async ({ page }) => {
|
||||
await page.goto('http://localhost:4001/rundown');
|
||||
|
||||
// clear rundown
|
||||
await page.goto('http://localhost:4001/rundown');
|
||||
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||
|
||||
//create event
|
||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||
|
||||
//delete event
|
||||
await page.locator('#event-block div').filter({ hasText: '1' }).click();
|
||||
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Backspace');
|
||||
await expect(page.getByRole('button', { name: 'Create Event' })).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user