mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 14:39:06 +00:00
Update test time until (#1809)
* test views test timeline * timeline show seconds when less than 2m * fix: countown typings * refactor: backstage schedule item * chore: lint
This commit is contained in:
@@ -71,7 +71,7 @@ function OperatorEvent({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={operatorClasses} ref={selectedRef} onContextMenu={handleLongPress} {...mouseHandlers}>
|
<div className={operatorClasses} data-testid={cue} ref={selectedRef} onContextMenu={handleLongPress} {...mouseHandlers}>
|
||||||
<div className={style.binder} style={{ ...cueColours }}>
|
<div className={style.binder} style={{ ...cueColours }}>
|
||||||
<span className={style.cue}>{cue}</span>
|
<span className={style.cue}>{cue}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -167,5 +167,5 @@ function TimeUntil({ timeStart, delay, dayOffset, totalGap, isLinkedToLoaded }:
|
|||||||
const isDue = timeUntil < MILLIS_PER_SECOND;
|
const isDue = timeUntil < MILLIS_PER_SECOND;
|
||||||
const timeUntilString = isDue ? 'DUE' : `${formatDuration(Math.abs(timeUntil), timeUntil > 2 * MILLIS_PER_MINUTE)}`;
|
const timeUntilString = isDue ? 'DUE' : `${formatDuration(Math.abs(timeUntil), timeUntil > 2 * MILLIS_PER_MINUTE)}`;
|
||||||
|
|
||||||
return <span className={style.timeUntil}>{timeUntilString}</span>;
|
return <span className={style.timeUntil} data-testid='time-until'>{timeUntilString}</span>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function StartTimes() {
|
|||||||
<Tooltip text='Planned start time' render={<TbCalendarPin className={style.icon} />} />
|
<Tooltip text='Planned start time' render={<TbCalendarPin className={style.icon} />} />
|
||||||
<span className={cx([style.time, plannedStart === null && style.muted])}>{plannedStartText}</span>
|
<span className={cx([style.time, plannedStart === null && style.muted])}>{plannedStartText}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.labelledElement}>
|
<div className={style.labelledElement} data-testid='actual-start-time'>
|
||||||
<Tooltip text='Actual start time' render={<TbCalendarClock className={style.icon} />} />
|
<Tooltip text='Actual start time' render={<TbCalendarClock className={style.icon} />} />
|
||||||
<span className={cx([style.time, actualStart === null && style.muted])}>{formattedTime(actualStart)}</span>
|
<span className={cx([style.time, actualStart === null && style.muted])}>{formattedTime(actualStart)}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export default function Schedule({ className }: ScheduleProps) {
|
|||||||
skip={event.skip}
|
skip={event.skip}
|
||||||
title={event.title}
|
title={event.title}
|
||||||
timeEnd={event.timeEnd}
|
timeEnd={event.timeEnd}
|
||||||
|
cue={event.cue}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type ScheduleItemProps = Pick<
|
|||||||
| 'skip'
|
| 'skip'
|
||||||
| 'title'
|
| 'title'
|
||||||
| 'timeEnd'
|
| 'timeEnd'
|
||||||
|
| 'cue'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export default function ScheduleItem({
|
export default function ScheduleItem({
|
||||||
@@ -43,84 +44,78 @@ export default function ScheduleItem({
|
|||||||
skip,
|
skip,
|
||||||
title,
|
title,
|
||||||
timeEnd,
|
timeEnd,
|
||||||
|
cue,
|
||||||
}: ScheduleItemProps) {
|
}: ScheduleItemProps) {
|
||||||
const { showExpected } = useScheduleOptions();
|
const { showExpected } = useScheduleOptions();
|
||||||
|
|
||||||
if (showExpected) {
|
|
||||||
return (
|
|
||||||
<ExpectedScheduleItem
|
|
||||||
timeStart={timeStart}
|
|
||||||
dayOffset={dayOffset}
|
|
||||||
delay={delay}
|
|
||||||
totalGap={totalGap}
|
|
||||||
isLinkedToLoaded={isLinkedToLoaded}
|
|
||||||
countToEnd={countToEnd}
|
|
||||||
duration={duration}
|
|
||||||
colour={colour}
|
|
||||||
skip={skip}
|
|
||||||
title={title}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delay > 0) {
|
|
||||||
return (
|
|
||||||
<DelayedScheduleItem
|
|
||||||
timeStart={timeStart}
|
|
||||||
delay={delay}
|
|
||||||
colour={colour}
|
|
||||||
skip={skip}
|
|
||||||
timeEnd={timeEnd}
|
|
||||||
title={title}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = formatTime(timeStart, formatOptions);
|
|
||||||
const end = formatTime(timeEnd, formatOptions);
|
|
||||||
return (
|
return (
|
||||||
<li className={cx(['entry', skip && 'entry--skip'])}>
|
<li className={cx(['entry', skip && 'entry--skip'])} data-testid={cue}>
|
||||||
<div className='entry-times'>
|
<div className='entry-times'>
|
||||||
<span className='entry-colour' style={{ backgroundColor: colour }} />
|
{showExpected ? (
|
||||||
<SuperscriptTime time={start} />
|
<ExpectedScheduleItem
|
||||||
→
|
timeStart={timeStart}
|
||||||
<SuperscriptTime time={end} />
|
dayOffset={dayOffset}
|
||||||
|
delay={delay}
|
||||||
|
totalGap={totalGap}
|
||||||
|
isLinkedToLoaded={isLinkedToLoaded}
|
||||||
|
countToEnd={countToEnd}
|
||||||
|
duration={duration}
|
||||||
|
colour={colour}
|
||||||
|
/>
|
||||||
|
) : delay > 0 ? (
|
||||||
|
<DelayedScheduleItem timeStart={timeStart} delay={delay} colour={colour} timeEnd={timeEnd} />
|
||||||
|
) : (
|
||||||
|
<PlannedScheduleItem timeStart={timeStart} timeEnd={timeEnd} colour={colour} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className='entry-title'>{title}</div>
|
<div className='entry-title'>{title}</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function PlannedScheduleItem({
|
||||||
|
timeStart,
|
||||||
|
timeEnd,
|
||||||
|
colour,
|
||||||
|
}: Pick<ScheduleItemProps, 'timeStart' | 'timeEnd' | 'colour'>) {
|
||||||
|
const start = formatTime(timeStart, formatOptions);
|
||||||
|
const end = formatTime(timeEnd, formatOptions);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className='entry-colour' style={{ backgroundColor: colour }} />
|
||||||
|
<SuperscriptTime time={start} />
|
||||||
|
→
|
||||||
|
<SuperscriptTime time={end} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function DelayedScheduleItem({
|
function DelayedScheduleItem({
|
||||||
timeStart,
|
timeStart,
|
||||||
timeEnd,
|
timeEnd,
|
||||||
title,
|
|
||||||
colour,
|
colour,
|
||||||
skip,
|
|
||||||
delay,
|
delay,
|
||||||
}: Pick<ScheduleItemProps, 'timeStart' | 'timeEnd' | 'title' | 'colour' | 'skip' | 'delay'>) {
|
}: Pick<ScheduleItemProps, 'timeStart' | 'timeEnd' | 'colour' | 'delay'>) {
|
||||||
const start = formatTime(timeStart, formatOptions);
|
const start = formatTime(timeStart, formatOptions);
|
||||||
const end = formatTime(timeEnd, formatOptions);
|
const end = formatTime(timeEnd, formatOptions);
|
||||||
const delayedStart = formatTime(timeStart + delay, formatOptions);
|
const delayedStart = formatTime(timeStart + delay, formatOptions);
|
||||||
const delayedEnd = formatTime(timeEnd + delay, formatOptions);
|
const delayedEnd = formatTime(timeEnd + delay, formatOptions);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className={cx(['entry', skip && 'entry--skip'])}>
|
<>
|
||||||
<div className='entry-times'>
|
<span className='entry-times--delayed'>
|
||||||
<span className='entry-times--delayed'>
|
<span className='entry-colour' style={{ backgroundColor: colour }} />
|
||||||
<span className='entry-colour' style={{ backgroundColor: colour }} />
|
<SuperscriptTime time={start} />
|
||||||
<SuperscriptTime time={start} />
|
→
|
||||||
→
|
<SuperscriptTime time={end} />
|
||||||
<SuperscriptTime time={end} />
|
</span>
|
||||||
</span>
|
<span className='entry-times--delay'>
|
||||||
<span className='entry-times--delay'>
|
<SuperscriptTime time={delayedStart} />
|
||||||
<SuperscriptTime time={delayedStart} />
|
→
|
||||||
→
|
<SuperscriptTime time={delayedEnd} />
|
||||||
<SuperscriptTime time={delayedEnd} />
|
</span>
|
||||||
</span>
|
</>
|
||||||
</div>
|
|
||||||
<div className='entry-title'>{title}</div>
|
|
||||||
</li>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +128,7 @@ function ExpectedScheduleItem({
|
|||||||
countToEnd,
|
countToEnd,
|
||||||
colour,
|
colour,
|
||||||
duration,
|
duration,
|
||||||
skip,
|
}: Omit<ScheduleItemProps, 'timeEnd' | 'cue' | 'skip' | 'title'>) {
|
||||||
title,
|
|
||||||
}: Omit<ScheduleItemProps, 'timeEnd'>) {
|
|
||||||
const expectedStartData = useExpectedStartData();
|
const expectedStartData = useExpectedStartData();
|
||||||
const { expectedStart, expectedEnd, plannedEnd } = getExpectedTimesFromExtendedEvent(
|
const { expectedStart, expectedEnd, plannedEnd } = getExpectedTimesFromExtendedEvent(
|
||||||
{
|
{
|
||||||
@@ -151,15 +144,12 @@ function ExpectedScheduleItem({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className={cx(['entry', skip && 'entry--skip'])}>
|
<>
|
||||||
<div className='entry-times'>
|
<span className='entry-colour' style={{ backgroundColor: colour }} />
|
||||||
<span className='entry-colour' style={{ backgroundColor: colour }} />
|
<ExpectedTime expectedTime={expectedStart} plannedTime={timeStart} />
|
||||||
<ExpectedTime expectedTime={expectedStart} plannedTime={timeStart} />
|
→
|
||||||
→
|
<ExpectedTime expectedTime={expectedEnd} plannedTime={plannedEnd} />
|
||||||
<ExpectedTime expectedTime={expectedEnd} plannedTime={plannedEnd} />
|
</>
|
||||||
</div>
|
|
||||||
<div className='entry-title'>{title}</div>
|
|
||||||
</li>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { IoArrowBack, IoClose, IoSaveOutline } from 'react-icons/io5';
|
import { IoArrowBack, IoClose, IoSaveOutline } from 'react-icons/io5';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { EntryId, OntimeEvent } from 'ontime-types';
|
import { EntryId, PlayableEvent } from 'ontime-types';
|
||||||
|
|
||||||
import Button from '../../common/components/buttons/Button';
|
import Button from '../../common/components/buttons/Button';
|
||||||
import { cx } from '../../common/utils/styleUtils';
|
import { cx } from '../../common/utils/styleUtils';
|
||||||
@@ -12,7 +12,7 @@ import { makeSubscriptionsUrl } from './countdown.utils';
|
|||||||
import './Countdown.scss';
|
import './Countdown.scss';
|
||||||
|
|
||||||
interface CountdownSelectProps {
|
interface CountdownSelectProps {
|
||||||
events: OntimeEvent[];
|
events: PlayableEvent[];
|
||||||
subscriptions: EntryId[];
|
subscriptions: EntryId[];
|
||||||
disableEdit: () => void;
|
disableEdit: () => void;
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ export default function CountdownSelect({ events, subscriptions, disableEdit }:
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='list-container'>
|
<div className='list-container'>
|
||||||
{events.map((event: OntimeEvent, index: number) => {
|
{events.map((event, index) => {
|
||||||
const title = event.title || '{no title}';
|
const title = event.title || '{no title}';
|
||||||
const isSelected = selectedIds.has(event.id);
|
const isSelected = selectedIds.has(event.id);
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ export default function CountdownSubscriptions({ subscribedEvents, goToEditMode
|
|||||||
key={event.id}
|
key={event.id}
|
||||||
ref={isLive ? selectedRef : undefined}
|
ref={isLive ? selectedRef : undefined}
|
||||||
className={cx(['sub', isLive && 'sub--live', isArmed && 'sub--armed'])}
|
className={cx(['sub', isLive && 'sub--live', isArmed && 'sub--armed'])}
|
||||||
|
data-testid={event.cue}
|
||||||
>
|
>
|
||||||
<div className='sub__binder' style={{ '--user-color': event.colour }} />
|
<div className='sub__binder' style={{ '--user-color': event.colour }} />
|
||||||
<ScheduleTime event={countdownEvent} showExpected={showExpected} />
|
<ScheduleTime event={countdownEvent} showExpected={showExpected} />
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: Timel
|
|||||||
isLinkedToLoaded={event.isLinkedToLoaded}
|
isLinkedToLoaded={event.isLinkedToLoaded}
|
||||||
dayOffset={event.dayOffset}
|
dayOffset={event.dayOffset}
|
||||||
title={event.title}
|
title={event.title}
|
||||||
|
cue={event.cue}
|
||||||
width={position.width}
|
width={position.width}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ interface TimelineEntryProps {
|
|||||||
isLinkedToLoaded: boolean;
|
isLinkedToLoaded: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
width: number;
|
width: number;
|
||||||
|
cue: string;
|
||||||
ref?: RefObject<HTMLDivElement | null>;
|
ref?: RefObject<HTMLDivElement | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ export function TimelineEntry({
|
|||||||
isLinkedToLoaded,
|
isLinkedToLoaded,
|
||||||
title,
|
title,
|
||||||
width,
|
width,
|
||||||
|
cue,
|
||||||
ref,
|
ref,
|
||||||
}: TimelineEntryProps) {
|
}: TimelineEntryProps) {
|
||||||
const formattedStartTime = formatTime(start, formatOptions);
|
const formattedStartTime = formatTime(start, formatOptions);
|
||||||
@@ -67,6 +69,7 @@ export function TimelineEntry({
|
|||||||
left: `${left}px`,
|
left: `${left}px`,
|
||||||
width: `${width}px`,
|
width: `${width}px`,
|
||||||
}}
|
}}
|
||||||
|
data-testid={cue}
|
||||||
>
|
>
|
||||||
{status === 'live' ? <ActiveBlock /> : <div data-status={status} className={style.timelineBlock} />}
|
{status === 'live' ? <ActiveBlock /> : <div data-status={status} className={style.timelineBlock} />}
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
color: $red-500;
|
color: $red-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-content--next {
|
.section-content--followedBy .section-content--next {
|
||||||
color: $green-500;
|
color: $green-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { OntimeEvent } from 'ontime-types';
|
import { OntimeEvent } from 'ontime-types';
|
||||||
|
import { MILLIS_PER_MINUTE } from 'ontime-utils';
|
||||||
|
|
||||||
import { useExpectedStartData } from '../../common/hooks/useSocket';
|
import { useExpectedStartData } from '../../common/hooks/useSocket';
|
||||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||||
@@ -30,7 +31,7 @@ export default function TimelineSections({ now, next, followedBy }: TimelineSect
|
|||||||
if (timeToStart <= 0) {
|
if (timeToStart <= 0) {
|
||||||
nextStatus = dueText;
|
nextStatus = dueText;
|
||||||
} else {
|
} else {
|
||||||
nextStatus = formatDuration(timeToStart);
|
nextStatus = formatDuration(timeToStart, timeToStart > MILLIS_PER_MINUTE * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ export default function TimelineSections({ now, next, followedBy }: TimelineSect
|
|||||||
if (timeToStart <= 0) {
|
if (timeToStart <= 0) {
|
||||||
followedByStatus = dueText;
|
followedByStatus = dueText;
|
||||||
} else {
|
} else {
|
||||||
followedByStatus = formatDuration(timeToStart);
|
followedByStatus = formatDuration(timeToStart, timeToStart > MILLIS_PER_MINUTE * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ export default function TimelineSections({ now, next, followedBy }: TimelineSect
|
|||||||
title={getLocalizedString('timeline.followedby')}
|
title={getLocalizedString('timeline.followedby')}
|
||||||
status={followedByStatus}
|
status={followedByStatus}
|
||||||
content={followedByText}
|
content={followedByText}
|
||||||
category='next'
|
category='followedBy'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { MaybeString } from 'ontime-types';
|
|||||||
import { cx } from '../../../common/utils/styleUtils';
|
import { cx } from '../../../common/utils/styleUtils';
|
||||||
|
|
||||||
interface SectionProps {
|
interface SectionProps {
|
||||||
category: 'now' | 'next';
|
category: 'now' | 'next' | 'followedBy';
|
||||||
content: MaybeString;
|
content: MaybeString;
|
||||||
title: string;
|
title: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
@@ -16,7 +16,7 @@ function TimelineSection({ category, content, title, status }: SectionProps) {
|
|||||||
const sectionClasses = cx(['section', category === 'now' && 'section--now']);
|
const sectionClasses = cx(['section', category === 'now' && 'section--now']);
|
||||||
const contentClasses = cx(['section-content', content ? `section-content--${category}` : 'section-content--subdue']);
|
const contentClasses = cx(['section-content', content ? `section-content--${category}` : 'section-content--subdue']);
|
||||||
return (
|
return (
|
||||||
<div className={sectionClasses}>
|
<div className={sectionClasses} data-testid={category}>
|
||||||
<div className='section-title'>
|
<div className='section-title'>
|
||||||
<span className='section-title__label'>{title}</span>
|
<span className='section-title__label'>{title}</span>
|
||||||
{status && <span className='section-title__status'>{status}</span>}
|
{status && <span className='section-title__status'>{status}</span>}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
getTimeFrom,
|
getTimeFrom,
|
||||||
isNewLatest,
|
isNewLatest,
|
||||||
MILLIS_PER_HOUR,
|
MILLIS_PER_HOUR,
|
||||||
|
MILLIS_PER_MINUTE,
|
||||||
} from 'ontime-utils';
|
} from 'ontime-utils';
|
||||||
|
|
||||||
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
||||||
@@ -81,7 +82,7 @@ export function getStatusLabel(timeToStart: number, status: ProgressStatus): str
|
|||||||
return 'pending';
|
return 'pending';
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatDuration(timeToStart);
|
return formatDuration(timeToStart, timeToStart > MILLIS_PER_MINUTE * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ScopedRundownData {
|
interface ScopedRundownData {
|
||||||
|
|||||||
@@ -1,77 +1,125 @@
|
|||||||
import { expect, test } from '@playwright/test';
|
import { expect, Locator, Page, test } from '@playwright/test';
|
||||||
|
|
||||||
test('time until absolute', async ({ page }) => {
|
test('time until absolute', async ({ context }) => {
|
||||||
await page.goto('http://localhost:4001/editor');
|
const editor = await context.newPage();
|
||||||
|
const op = await context.newPage();
|
||||||
|
const timeline = await context.newPage();
|
||||||
|
const countdown = await context.newPage();
|
||||||
|
await editor.goto('/editor');
|
||||||
|
await op.goto('/op');
|
||||||
|
await timeline.goto('/timeline');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Clear all' }).click();
|
await editor.getByRole('button', { name: 'Clear all' }).click();
|
||||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
await editor.getByRole('button', { name: 'Delete all' }).click();
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
await editor.getByRole('button', { name: 'Create Event' }).click();
|
||||||
await page.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
await editor.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
||||||
await page.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
await editor.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
||||||
await page.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
await editor.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Absolute' }).click();
|
await editor.getByTestId('entry-1').getByTestId('rundown-event').click();
|
||||||
await page.getByTestId('entry-1').getByLabel('Start event').click();
|
const ids = new Array<string>();
|
||||||
await expect(page.getByTestId('offset')).not.toContainText('00:00:00'); // This might be a bad test requires that the test is not run at 0h
|
ids.push(await editor.getByTestId('editor-container').getByLabel('Event ID (read only)').inputValue());
|
||||||
await page.getByLabel('Pause event').click();
|
await editor.getByTestId('entry-2').getByTestId('rundown-event').click();
|
||||||
|
ids.push(await editor.getByTestId('editor-container').getByLabel('Event ID (read only)').inputValue());
|
||||||
|
await editor.getByTestId('entry-3').getByTestId('rundown-event').click();
|
||||||
|
ids.push(await editor.getByTestId('editor-container').getByLabel('Event ID (read only)').inputValue());
|
||||||
|
await editor.getByTestId('entry-4').getByTestId('rundown-event').click();
|
||||||
|
ids.push(await editor.getByTestId('editor-container').getByLabel('Event ID (read only)').inputValue());
|
||||||
|
|
||||||
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('9m');
|
await countdown.goto('/countdown?' + ids.join('&sub='));
|
||||||
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('19m');
|
|
||||||
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('29m');
|
|
||||||
|
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
const locatorElements2 = [
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').fill('6h');
|
editor.getByTestId('entry-2').getByTestId('rundown-event'),
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
op.getByTestId('2').getByTestId('time-until'),
|
||||||
|
timeline.getByTestId('2'),
|
||||||
|
timeline.getByTestId('next'),
|
||||||
|
countdown.getByTestId('2'),
|
||||||
|
];
|
||||||
|
const locatorElements3 = [
|
||||||
|
editor.getByTestId('entry-3').getByTestId('rundown-event'),
|
||||||
|
op.getByTestId('3').getByTestId('time-until'),
|
||||||
|
timeline.getByTestId('3'),
|
||||||
|
timeline.getByTestId('followedBy'),
|
||||||
|
countdown.getByTestId('3'),
|
||||||
|
];
|
||||||
|
const locatorElements4 = [
|
||||||
|
editor.getByTestId('entry-4').getByTestId('rundown-event'),
|
||||||
|
op.getByTestId('4').getByTestId('time-until'),
|
||||||
|
timeline.getByTestId('4'),
|
||||||
|
countdown.getByTestId('4'),
|
||||||
|
];
|
||||||
|
|
||||||
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('5h59m');
|
await editor.getByRole('button', { name: 'Absolute' }).click();
|
||||||
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('6h9m');
|
await editor.getByTestId('entry-1').getByLabel('Start event').click();
|
||||||
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('6h19m');
|
await expect(editor.getByTestId('offset')).not.toContainText('00:00:00'); // This might be a bad test requires that the test is not run at 0h
|
||||||
|
await editor.getByLabel('Pause event').click();
|
||||||
|
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
await testTimes(locatorElements2, '9m');
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').fill('30s');
|
await testTimes(locatorElements3, '19m');
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
await testTimes(locatorElements4, '29m');
|
||||||
|
|
||||||
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('30s');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
||||||
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('10m');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').fill('6h');
|
||||||
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('20m');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
||||||
|
|
||||||
|
await testTimes(locatorElements2, '5h59m');
|
||||||
|
await testTimes(locatorElements3, '6h9m');
|
||||||
|
await testTimes(locatorElements4, '6h19m');
|
||||||
|
|
||||||
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
||||||
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').fill('30s');
|
||||||
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
||||||
|
|
||||||
|
await expect(editor.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('30s');
|
||||||
|
await expect(editor.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('10m');
|
||||||
|
await expect(editor.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('20m');
|
||||||
|
|
||||||
|
await testTimes(locatorElements2, '30s');
|
||||||
|
await testTimes(locatorElements3, '10m');
|
||||||
|
await testTimes(locatorElements4, '20m');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('time until relative', async ({ page }) => {
|
async function testTimes(locators: Locator[], value: string) {
|
||||||
await page.goto('http://localhost:4001/editor');
|
await locators.map(async (locator) => await expect(locator).toContainText(value));
|
||||||
|
}
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Clear all' }).click();
|
test('time until relative', async ({ context }) => {
|
||||||
await page.getByRole('button', { name: 'Delete all' }).click();
|
const editor = await context.newPage();
|
||||||
|
editor.goto('http://localhost:4001/editor');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
await editor.getByRole('button', { name: 'Clear all' }).click();
|
||||||
await page.getByRole('button', { name: 'Event' }).nth(4).click();
|
await editor.getByRole('button', { name: 'Delete all' }).click();
|
||||||
await page.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
|
||||||
await page.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Relative' }).click();
|
await editor.getByRole('button', { name: 'Create Event' }).click();
|
||||||
await page.getByTestId('entry-1').getByLabel('Start event').click();
|
await editor.getByRole('button', { name: 'Event' }).nth(4).click();
|
||||||
await expect(page.getByTestId('offset')).toContainText('00:00:00'); // This might be a bad test as it ruires the evaluation to happen within 1s
|
await editor.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
||||||
await page.getByLabel('Pause event').click();
|
await editor.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
||||||
|
|
||||||
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('9m');
|
await editor.getByRole('button', { name: 'Relative' }).click();
|
||||||
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('19m');
|
await editor.getByTestId('entry-1').getByLabel('Start event').click();
|
||||||
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('29m');
|
await expect(editor.getByTestId('offset')).toContainText('00:00:00'); // This might be a bad test as it ruires the evaluation to happen within 1s
|
||||||
|
await editor.getByLabel('Pause event').click();
|
||||||
|
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
await expect(editor.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('9m');
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').fill('6h');
|
await expect(editor.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('19m');
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
await expect(editor.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('29m');
|
||||||
|
|
||||||
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('5h59m');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
||||||
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('6h9m');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').fill('6h');
|
||||||
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('6h19m');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
||||||
|
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
await expect(editor.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('5h59m');
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').fill('30s');
|
await expect(editor.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('6h9m');
|
||||||
await page.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
await expect(editor.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('6h19m');
|
||||||
|
|
||||||
await expect(page.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('30s');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').click();
|
||||||
await expect(page.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('10m');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').fill('30s');
|
||||||
await expect(page.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('20m');
|
await editor.getByTestId('entry-1').getByTestId('time-input-duration').press('Enter');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Absolute' }).click();
|
await expect(editor.getByTestId('entry-2').getByTestId('rundown-event')).toContainText('30s');
|
||||||
|
await expect(editor.getByTestId('entry-3').getByTestId('rundown-event')).toContainText('10m');
|
||||||
|
await expect(editor.getByTestId('entry-4').getByTestId('rundown-event')).toContainText('20m');
|
||||||
|
|
||||||
|
await editor.getByRole('button', { name: 'Absolute' }).click();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user