- Added NightScreen component for displaying night mode information and alerts. - Introduced NextStops component to show upcoming stops during a journey. - Implemented logic for determining night mode activation based on schedule and user settings. - Created journey utility functions to manage onward journey data and stop information. - Updated tests to cover new night mode features and journey logic. - Added fixture for testing night mode scenarios with specific timestamps. - Removed QR code from night screen for a cleaner UI experience. - Enhanced admin settings to manage night mode configurations.
80 lines
6.4 KiB
JavaScript
80 lines
6.4 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { nightWindow } from '../src/lib/night.ts';
|
|
import { defaultSettings } from '../src/lib/storage.ts';
|
|
const at = value => Date.parse(`${value}+03:00`);
|
|
const trip = (id, time, serviceDate = time.slice(0,10), status = 'scheduled', routeId = 1) => ({ id, routeId, routeNumber: String(routeId), routeName: 'Маршрут', destination: 'Автовокзал', type: 'bus', scheduledAt: new Date(at(time)).toISOString(), scheduledTime: time.slice(11,16), serviceDate, source: 'schedule', note: '', status });
|
|
const trips = [trip('last', '2026-10-10T23:00:00'), trip('first', '2026-10-11T05:40:00'), trip('later', '2026-10-11T22:00:00')];
|
|
const check = (now, departures = trips, settings = defaultSettings, available = true) => nightWindow(settings, departures, at(now), available);
|
|
test('night starts only after the final scheduled trip and an overnight break longer than two hours', () => {
|
|
assert.equal(check('2026-10-10T22:59:00').active, false);
|
|
assert.equal(check('2026-10-10T23:00:30').active, false);
|
|
const night = check('2026-10-10T23:02:00'); assert.equal(night.active, true); assert.equal(night.first.id, 'first'); assert.equal(night.completedToday, true);
|
|
assert.equal(check('2026-10-11T03:40:00').active, true);
|
|
const short = [trips[0], trip('short', '2026-10-11T01:00:00'), trips[2]];
|
|
assert.equal(check('2026-10-10T23:02:00', short).active, false);
|
|
assert.equal(check('2026-10-10T23:02:00', [trips[0], trip('long', '2026-10-11T01:01:00'), trips[2]]).active, true);
|
|
});
|
|
test('a daytime gap does not declare movement complete', () => {
|
|
const day = [trip('early','2026-10-11T06:00:00'),trip('late','2026-10-11T19:00:00')];
|
|
assert.equal(check('2026-10-11T12:00:00', day).active, false);
|
|
});
|
|
test('cold starts during the same break stay in night mode until the selected 60 or 45 minute boundary', () => {
|
|
assert.equal(check('2026-10-11T04:10:00').active,true);
|
|
assert.equal(check('2026-10-11T04:39:59').active,true);
|
|
assert.equal(check('2026-10-11T04:40:00').active,false);
|
|
assert.equal(check('2026-10-11T04:50:00',trips,{...defaultSettings,nightWakeMinutes:45}).active,true);
|
|
assert.equal(check('2026-10-11T04:55:00',trips,{...defaultSettings,nightWakeMinutes:45}).active,false);
|
|
});
|
|
test('midnight keeps night mode and the correct first trip date', () => {
|
|
const before = check('2026-10-10T23:40:00'), after = check('2026-10-11T00:05:00');
|
|
assert.equal(after.active,true);assert.equal(after.first.id,before.first.id);assert.equal(after.completedToday,false);assert.equal(after.first.scheduledTime,'05:40');
|
|
});
|
|
test('after-midnight arrivals keep their service day and cannot be hidden while approaching', () => {
|
|
const overnight = [trip('late','2026-10-11T00:15:00','2026-10-10'),...trips];
|
|
assert.equal(check('2026-10-11T00:14:00',overnight).active,false);
|
|
assert.equal(check('2026-10-11T00:15:30',overnight).active,false);
|
|
assert.equal(check('2026-10-11T00:17:00',overnight).active,true);
|
|
});
|
|
test('a calendar-day 00:40 continuation closes the previous night, while continuous overnight service and midday gaps do not', () => {
|
|
const closing = [trip('yesterday','2026-10-10T23:55:00'),trip('tail','2026-10-11T00:40:00'),trip('morning','2026-10-11T05:44:00'),trip('end','2026-10-11T23:00:00')];
|
|
assert.equal(check('2026-10-11T00:39:00',closing).active,false);
|
|
assert.equal(check('2026-10-11T00:40:30',closing).active,false);
|
|
const night=check('2026-10-11T02:00:00',closing);assert.equal(night.active,true);assert.equal(night.first.id,'morning');
|
|
assert.equal(check('2026-10-11T04:00:00',closing).active,true);
|
|
assert.equal(check('2026-10-11T04:44:00',closing).active,false);
|
|
assert.equal(check('2026-10-11T12:00:00',closing).active,false);
|
|
const continuous=[...closing,trip('one','2026-10-11T01:30:00'),trip('two','2026-10-11T02:20:00'),trip('three','2026-10-11T03:10:00')];
|
|
assert.equal(check('2026-10-11T04:00:00',continuous).active,false);
|
|
});
|
|
test('Avtovokzal midnight trip at 00:31 does not prevent night mode on startup at 03:31 before the 05:15 trip', () => {
|
|
const departures = [trip('last', '2026-10-10T23:55:00'), trip('tail', '2026-10-11T00:31:00'), trip('morning', '2026-10-11T05:15:00'), trip('later', '2026-10-11T23:55:00')];
|
|
assert.equal(check('2026-10-11T00:30:00', departures).active, false);
|
|
assert.equal(check('2026-10-11T00:31:59', departures).active, false);
|
|
const night = check('2026-10-11T03:31:00', departures);
|
|
assert.equal(night.active, true); assert.equal(night.first.scheduledTime, '05:15'); assert.equal(night.completedToday, false);
|
|
assert.equal(check('2026-10-11T04:14:59', departures).active, true);
|
|
assert.equal(check('2026-10-11T04:15:00', departures).active, false);
|
|
const wake45 = {...defaultSettings, nightWakeMinutes:45};
|
|
assert.equal(check('2026-10-11T04:15:00', departures, wake45).active, true);
|
|
assert.equal(check('2026-10-11T04:30:00', departures, wake45).active, false);
|
|
});
|
|
test('cancelled first trip is skipped; all cancelled, missing, stale, demo and disabled data cannot start night', () => {
|
|
const cancelled = [trips[0],{...trips[1],status:'cancelled'},trip('next','2026-10-11T06:00:00')];
|
|
assert.equal(check('2026-10-11T00:05:00',cancelled).first.id,'next');
|
|
for(const data of [[],[trips[0]],trips.map(d=>({...d,status:'cancelled'}))])assert.equal(check('2026-10-11T00:05:00',data).active,false);
|
|
assert.equal(check('2026-10-11T00:05:00',trips,defaultSettings,false).active,false);
|
|
assert.equal(check('2026-10-11T00:05:00',trips,{...defaultSettings,demo:true}).active,false);
|
|
assert.equal(check('2026-10-11T00:05:00',trips,{...defaultSettings,nightMode:'off'}).active,false);
|
|
});
|
|
test('route selection recalculates the break; unordered data and year boundaries are safe', () => {
|
|
const mixed = [trip('other','2026-10-11T00:20:00','2026-10-10','scheduled',2),trip('other-first','2026-10-11T04:00:00','2026-10-11','scheduled',2),...trips];
|
|
assert.equal(check('2026-10-11T00:10:00',mixed).active,false);
|
|
const filteredSettings = {...defaultSettings,routeFilter:'1'};
|
|
assert.equal(check('2026-10-11T00:10:00',mixed,filteredSettings).active,true);
|
|
assert.equal(check('2026-10-11T03:31:00',mixed).active,false);
|
|
assert.equal(check('2026-10-11T03:31:00',mixed,filteredSettings).active,true);
|
|
const year = [trip('year-last','2026-12-31T23:00:00'),trip('year-first','2027-01-01T06:00:00')].reverse();
|
|
assert.equal(check('2027-01-01T00:10:00',year).first.id,'year-first');
|
|
});
|