Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/concierge/src/app/staff/staff-listing.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,14 @@ export class StaffListingComponent extends AsyncHandler {

constructor() {
super();
effect(() => {
effect((onCleanup) => {
this.user_list();
this.timeout('scroll', () => this.onScroll({}), 30);
// `onScroll` reads the document, so the timer must not outlive the
// effect. Relying on `ngOnDestroy` alone is not enough: the effect
// can flush during teardown and schedule a fresh timer after the
// base class has already cleared them.
onCleanup(() => this.clearTimeout('scroll'));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,21 @@ describe('ParkingBookingsListComponent', () => {

it('should show all day when the booking matches the bookable period', () => {
bookable_hours = { start: 8, end: 17 };
selected_date = new Date(2026, 6, 21, 8).valueOf();
// `isParkingAllDayBooking` converts the booking into `timezone`
// (Australia/Perth here) before checking that it starts and ends on the
// same day. Building these from machine-local hours only holds while
// the runner sits near +08:00 — on a UTC runner the end lands on the
// following Perth day and the booking stops reading as all-day. So
// state the instants in Perth, which is what the assertion is about.
selected_date = new Date('2026-07-21T08:00:00+08:00').valueOf();
bookings = [
{
id: 'booking-1',
asset_id: 'bay-1',
status: 'approved',
all_day: true,
date: new Date(2026, 6, 21, 8).valueOf(),
date_end: new Date(2026, 6, 21, 17).valueOf(),
date: new Date('2026-07-21T08:00:00+08:00').valueOf(),
date_end: new Date('2026-07-21T17:00:00+08:00').valueOf(),
duration: 9 * 60,
} as unknown as Booking,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,11 @@ describe('ParkingMapComponent', () => {

it('should select a one-hour parking availability window', () => {
const state = spectator.inject(ParkingStateService);
const date = new Date('2026-07-13T09:30:00+10:00').valueOf();
// `setAvailabilityHour` picks the hour with `Date#setHours`, which is
// the machine's timezone, so both the input and the expectation are
// built the same way. Writing either as a fixed UTC offset would pin
// the test to a runner in that zone.
const date = new Date(2026, 6, 13, 9, 30).valueOf();
Object.defineProperty(spectator.component, 'options', {
value: () => ({ date, all_day: true, zones: [] }),
configurable: true,
Expand All @@ -130,7 +134,7 @@ describe('ParkingMapComponent', () => {
spectator.component.setAvailabilityHour(14);

expect(state.setOptions).toHaveBeenCalledWith({
date: new Date('2026-07-13T14:00:00+10:00').valueOf(),
date: new Date(2026, 6, 13, 14, 0, 0, 0).valueOf(),
all_day: false,
duration: 60,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,12 @@ describe('SiteAttendanceReportService', () => {
});

it('should export report data', () => {
// The filename is built with date-fns `format`, which renders in the
// machine's timezone, so the range is set the same way. A UTC instant
// here names the previous day once the runner is west of Greenwich.
spectator.service.setOptions({
start: new Date('2026-04-06T00:00:00Z').valueOf(),
end: new Date('2026-04-06T23:59:59Z').valueOf(),
start: new Date(2026, 3, 6).valueOf(),
end: new Date(2026, 3, 6, 23, 59, 59).valueOf(),
});
(spectator.service as any)._report.set({
business_days: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ describe('StaffListingComponent', () => {

beforeEach(() => (spectator = createComponent()));

// The component schedules a 30ms timer that reads the document. This file
// finishes well inside that window, so without an explicit destroy the
// timer outlives the test environment and throws `document is not defined`
// during teardown, failing the whole run with every test passing.
afterEach(() => spectator?.fixture?.destroy());

it('should create component', () => {
expect(spectator.component).toBeTruthy();
});
Expand Down
Loading