test: cover queues and court rotation and document release test choice
This commit is contained in:
1 parent
1d660a3c40
commit
0757e0df76
10 files changed
+730
-39
No files matched your search
@@ -1,16 +1,56 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { db } from 'db';
|
||||
import { CourtServiceJudgeService } from './court.service.judge.service';
|
||||
|
||||
describe('CourtServiceJudgeService', () => {
|
||||
describe('CourtServiceJudgeService persistence', () => {
|
||||
let service: CourtServiceJudgeService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
beforeEach(async () => {
|
||||
await db.courtServiceJudges.clear();
|
||||
service = TestBed.inject(CourtServiceJudgeService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
afterEach(async () => {
|
||||
TestBed.resetTestingModule();
|
||||
await db.courtServiceJudges.clear();
|
||||
});
|
||||
|
||||
it('saves an assignment and returns its generated ID', async () => {
|
||||
const id = await service.save({ umpireId: 10, courtNo: 2 });
|
||||
expect(await db.courtServiceJudges.get(id)).toEqual({
|
||||
id,
|
||||
umpireId: 10,
|
||||
courtNo: 2
|
||||
});
|
||||
});
|
||||
|
||||
it('updates an assignment without changing its court', async () => {
|
||||
const id = await service.save({ umpireId: 10, courtNo: 2 });
|
||||
expect(await service.update(id, { umpireId: 20 })).toBe(1);
|
||||
expect(await db.courtServiceJudges.get(id)).toEqual({
|
||||
id,
|
||||
umpireId: 20,
|
||||
courtNo: 2
|
||||
});
|
||||
expect(await service.update(id + 100, { umpireId: 30 })).toBe(0);
|
||||
});
|
||||
|
||||
it('deletes only the selected assignment', async () => {
|
||||
const id = await service.save({ umpireId: 10, courtNo: 1 });
|
||||
const retained = await service.save({ umpireId: 20, courtNo: 2 });
|
||||
await service.delete(id);
|
||||
expect(await db.courtServiceJudges.toArray()).toEqual([
|
||||
{ id: retained, umpireId: 20, courtNo: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes by official ID while retaining other courts', async () => {
|
||||
await service.save({ umpireId: 10, courtNo: 1 });
|
||||
const id = await service.save({ umpireId: 20, courtNo: 2 });
|
||||
await service.removeByUmpireId(10);
|
||||
await service.removeByUmpireId(999);
|
||||
expect(await db.courtServiceJudges.toArray()).toEqual([
|
||||
{ id, umpireId: 20, courtNo: 2 }
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,56 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { db } from 'db';
|
||||
import { CourtUmpireService } from './court.umpire.service';
|
||||
|
||||
describe('CourtUmpireService', () => {
|
||||
describe('CourtUmpireService persistence', () => {
|
||||
let service: CourtUmpireService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
beforeEach(async () => {
|
||||
await db.courtUmpires.clear();
|
||||
service = TestBed.inject(CourtUmpireService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
afterEach(async () => {
|
||||
TestBed.resetTestingModule();
|
||||
await db.courtUmpires.clear();
|
||||
});
|
||||
|
||||
it('saves an assignment and returns its generated ID', async () => {
|
||||
const id = await service.save({ umpireId: 10, courtNo: 2 });
|
||||
expect(await db.courtUmpires.get(id)).toEqual({
|
||||
id,
|
||||
umpireId: 10,
|
||||
courtNo: 2
|
||||
});
|
||||
});
|
||||
|
||||
it('updates an assignment without changing its court', async () => {
|
||||
const id = await service.save({ umpireId: 10, courtNo: 2 });
|
||||
expect(await service.update(id, { umpireId: 20 })).toBe(1);
|
||||
expect(await db.courtUmpires.get(id)).toEqual({
|
||||
id,
|
||||
umpireId: 20,
|
||||
courtNo: 2
|
||||
});
|
||||
expect(await service.update(id + 100, { umpireId: 30 })).toBe(0);
|
||||
});
|
||||
|
||||
it('deletes only the selected assignment', async () => {
|
||||
const id = await service.save({ umpireId: 10, courtNo: 1 });
|
||||
const retained = await service.save({ umpireId: 20, courtNo: 2 });
|
||||
await service.delete(id);
|
||||
expect(await db.courtUmpires.toArray()).toEqual([
|
||||
{ id: retained, umpireId: 20, courtNo: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes by official ID while retaining other courts', async () => {
|
||||
await service.save({ umpireId: 10, courtNo: 1 });
|
||||
const id = await service.save({ umpireId: 20, courtNo: 2 });
|
||||
await service.removeByUmpireId(10);
|
||||
await service.removeByUmpireId(999);
|
||||
expect(await db.courtUmpires.toArray()).toEqual([
|
||||
{ id, umpireId: 20, courtNo: 2 }
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,62 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { db } from 'db';
|
||||
import { UmpireService } from './umpire.service';
|
||||
|
||||
describe('Umpire', () => {
|
||||
describe('UmpireService persistence', () => {
|
||||
let service: UmpireService;
|
||||
const official = {
|
||||
firstName: 'Alex',
|
||||
lastName: 'Smith',
|
||||
country: 'GB',
|
||||
gender: 'M'
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
beforeEach(async () => {
|
||||
await db.umpires.clear();
|
||||
service = TestBed.inject(UmpireService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
afterEach(async () => {
|
||||
TestBed.resetTestingModule();
|
||||
await db.umpires.clear();
|
||||
});
|
||||
|
||||
it('creates and retrieves a complete official record', async () => {
|
||||
const id = await service.create(official);
|
||||
expect(await service.getById(id)).toEqual({ ...official, id });
|
||||
});
|
||||
|
||||
it('updates selected fields while retaining the rest of the record', async () => {
|
||||
const id = await service.create(official);
|
||||
expect(await service.update(id, { country: 'HU' })).toBe(1);
|
||||
expect(await service.getById(id)).toEqual({
|
||||
...official,
|
||||
id,
|
||||
country: 'HU'
|
||||
});
|
||||
});
|
||||
|
||||
it('returns undefined and zero when reading or updating an absent official', async () => {
|
||||
expect(await service.getById(999)).toBeUndefined();
|
||||
expect(await service.update(999, { country: 'HU' })).toBe(0);
|
||||
});
|
||||
|
||||
it('deletes one official and retains the other', async () => {
|
||||
const id = await service.create(official);
|
||||
const retained = await service.create({ ...official, firstName: 'Sam' });
|
||||
await service.delete(id);
|
||||
expect(await service.getById(id)).toBeUndefined();
|
||||
expect(await service.getById(retained)).toEqual({
|
||||
...official,
|
||||
firstName: 'Sam',
|
||||
id: retained
|
||||
});
|
||||
});
|
||||
|
||||
it('clears all officials', async () => {
|
||||
await service.create(official);
|
||||
await service.create({ ...official, firstName: 'Sam' });
|
||||
await service.clear();
|
||||
expect(await db.umpires.count()).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,174 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { db } from 'db';
|
||||
import { WaitingServiceJudgesService } from './waiting-service-judges.service';
|
||||
|
||||
describe('WaitingServiceJudgesService', () => {
|
||||
describe('WaitingServiceJudgesService queue behavior', () => {
|
||||
let service: WaitingServiceJudgesService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
beforeEach(async () => {
|
||||
await db.waitingServiceJudges.clear();
|
||||
await db.umpires.clear();
|
||||
service = TestBed.inject(WaitingServiceJudgesService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
afterEach(async () => {
|
||||
TestBed.resetTestingModule();
|
||||
await db.waitingServiceJudges.clear();
|
||||
await db.umpires.clear();
|
||||
});
|
||||
|
||||
async function queue() {
|
||||
const items = await db.waitingServiceJudges.orderBy('order').toArray();
|
||||
return items.map((item) => [item.serviceJudgeId, item.order]);
|
||||
}
|
||||
|
||||
async function seed() {
|
||||
await service.add(10);
|
||||
await service.add(20);
|
||||
await service.add(30);
|
||||
}
|
||||
|
||||
it('starts an empty queue at one and appends in FIFO order', async () => {
|
||||
await seed();
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[20, 2],
|
||||
[30, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('appends after the greatest numeric order, regardless of insertion order', async () => {
|
||||
await db.waitingServiceJudges.bulkAdd([
|
||||
{ serviceJudgeId: 10, order: 9 },
|
||||
{ serviceJudgeId: 20, order: 2 }
|
||||
]);
|
||||
await service.add(30);
|
||||
expect(await queue()).toEqual([
|
||||
[20, 2],
|
||||
[10, 9],
|
||||
[30, 10]
|
||||
]);
|
||||
});
|
||||
|
||||
it('serializes concurrent appends with distinct consecutive orders', async () => {
|
||||
await Promise.all([service.add(10), service.add(20), service.add(30)]);
|
||||
const items = await queue();
|
||||
expect(items.map((item) => item[1])).toEqual([1, 2, 3]);
|
||||
expect(items.map((item) => item[0]).sort()).toEqual([10, 20, 30]);
|
||||
});
|
||||
|
||||
it('inserts at a requested position and shifts following officials', async () => {
|
||||
await seed();
|
||||
await service.add(40, 2);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[40, 2],
|
||||
[20, 3],
|
||||
[30, 4]
|
||||
]);
|
||||
});
|
||||
|
||||
it('moves an official toward the front', async () => {
|
||||
await seed();
|
||||
await service.moveToPosition(30, 1);
|
||||
expect(await queue()).toEqual([
|
||||
[30, 1],
|
||||
[10, 2],
|
||||
[20, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('moves an official toward the back', async () => {
|
||||
await seed();
|
||||
await service.moveToPosition(10, 3);
|
||||
expect(await queue()).toEqual([
|
||||
[20, 1],
|
||||
[30, 2],
|
||||
[10, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('leaves the queue unchanged for a missing official or unchanged position', async () => {
|
||||
await seed();
|
||||
await service.moveToPosition(999, 2);
|
||||
await service.moveToPosition(20, 2);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[20, 2],
|
||||
[30, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes by official ID and closes the gap', async () => {
|
||||
await seed();
|
||||
await service.removeByUmpireId(20);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[30, 2]
|
||||
]);
|
||||
await service.removeByUmpireId(999);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[30, 2]
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes by queue record ID rather than official ID', async () => {
|
||||
await service.add(10);
|
||||
const id = await service.add(20);
|
||||
await service.add(30);
|
||||
await service.remove(id);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[30, 2]
|
||||
]);
|
||||
});
|
||||
|
||||
it('normalizes gaps while preserving numeric ordering', async () => {
|
||||
await db.waitingServiceJudges.bulkAdd([
|
||||
{ serviceJudgeId: 10, order: 12 },
|
||||
{ serviceJudgeId: 20, order: 4 }
|
||||
]);
|
||||
await service.reinitOrders();
|
||||
expect(await queue()).toEqual([
|
||||
[20, 1],
|
||||
[10, 2]
|
||||
]);
|
||||
});
|
||||
|
||||
it('resolves the queue head to the complete official record', async () => {
|
||||
const official = {
|
||||
firstName: 'Alex',
|
||||
lastName: 'Smith',
|
||||
country: 'GB',
|
||||
gender: 'M'
|
||||
};
|
||||
const id = await db.umpires.add(official);
|
||||
await service.add(id);
|
||||
expect(await service.getCurrentUmpire()).toEqual({ ...official, id });
|
||||
});
|
||||
|
||||
it('returns undefined for an empty queue or a missing roster record', async () => {
|
||||
expect(await service.getCurrentUmpire()).toBeUndefined();
|
||||
await service.add(999);
|
||||
expect(await service.getCurrentUmpire()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('updates only the selected record order', async () => {
|
||||
const id = await service.add(10);
|
||||
await service.add(20);
|
||||
await service.updateOrder(id, 5);
|
||||
expect(await queue()).toEqual([
|
||||
[20, 2],
|
||||
[10, 5]
|
||||
]);
|
||||
});
|
||||
|
||||
it('clears the queue and restarts ordering at one', async () => {
|
||||
await seed();
|
||||
await service.clear();
|
||||
expect(await queue()).toEqual([]);
|
||||
await service.add(40);
|
||||
expect(await queue()).toEqual([[40, 1]]);
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,174 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { db } from 'db';
|
||||
import { WaitingUmpiresService } from './waiting-umpires.service';
|
||||
|
||||
describe('WaitingUmpiresService', () => {
|
||||
describe('WaitingUmpiresService queue behavior', () => {
|
||||
let service: WaitingUmpiresService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
beforeEach(async () => {
|
||||
await db.waitingUmpires.clear();
|
||||
await db.umpires.clear();
|
||||
service = TestBed.inject(WaitingUmpiresService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
afterEach(async () => {
|
||||
TestBed.resetTestingModule();
|
||||
await db.waitingUmpires.clear();
|
||||
await db.umpires.clear();
|
||||
});
|
||||
|
||||
async function queue() {
|
||||
const items = await db.waitingUmpires.orderBy('order').toArray();
|
||||
return items.map((item) => [item.umpireId, item.order]);
|
||||
}
|
||||
|
||||
async function seed() {
|
||||
await service.add(10);
|
||||
await service.add(20);
|
||||
await service.add(30);
|
||||
}
|
||||
|
||||
it('starts an empty queue at one and appends in FIFO order', async () => {
|
||||
await seed();
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[20, 2],
|
||||
[30, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('appends after the greatest numeric order, regardless of insertion order', async () => {
|
||||
await db.waitingUmpires.bulkAdd([
|
||||
{ umpireId: 10, order: 9 },
|
||||
{ umpireId: 20, order: 2 }
|
||||
]);
|
||||
await service.add(30);
|
||||
expect(await queue()).toEqual([
|
||||
[20, 2],
|
||||
[10, 9],
|
||||
[30, 10]
|
||||
]);
|
||||
});
|
||||
|
||||
it('serializes concurrent appends with distinct consecutive orders', async () => {
|
||||
await Promise.all([service.add(10), service.add(20), service.add(30)]);
|
||||
const items = await queue();
|
||||
expect(items.map((item) => item[1])).toEqual([1, 2, 3]);
|
||||
expect(items.map((item) => item[0]).sort()).toEqual([10, 20, 30]);
|
||||
});
|
||||
|
||||
it('inserts at a requested position and shifts following officials', async () => {
|
||||
await seed();
|
||||
await service.add(40, 2);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[40, 2],
|
||||
[20, 3],
|
||||
[30, 4]
|
||||
]);
|
||||
});
|
||||
|
||||
it('moves an official toward the front', async () => {
|
||||
await seed();
|
||||
await service.moveToPosition(30, 1);
|
||||
expect(await queue()).toEqual([
|
||||
[30, 1],
|
||||
[10, 2],
|
||||
[20, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('moves an official toward the back', async () => {
|
||||
await seed();
|
||||
await service.moveToPosition(10, 3);
|
||||
expect(await queue()).toEqual([
|
||||
[20, 1],
|
||||
[30, 2],
|
||||
[10, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('leaves the queue unchanged for a missing official or unchanged position', async () => {
|
||||
await seed();
|
||||
await service.moveToPosition(999, 2);
|
||||
await service.moveToPosition(20, 2);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[20, 2],
|
||||
[30, 3]
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes by official ID and closes the gap', async () => {
|
||||
await seed();
|
||||
await service.removeByUmpireId(20);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[30, 2]
|
||||
]);
|
||||
await service.removeByUmpireId(999);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[30, 2]
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes by queue record ID rather than official ID', async () => {
|
||||
await service.add(10);
|
||||
const id = await service.add(20);
|
||||
await service.add(30);
|
||||
await service.remove(id);
|
||||
expect(await queue()).toEqual([
|
||||
[10, 1],
|
||||
[30, 2]
|
||||
]);
|
||||
});
|
||||
|
||||
it('normalizes gaps while preserving numeric ordering', async () => {
|
||||
await db.waitingUmpires.bulkAdd([
|
||||
{ umpireId: 10, order: 12 },
|
||||
{ umpireId: 20, order: 4 }
|
||||
]);
|
||||
await service.reinitOrders();
|
||||
expect(await queue()).toEqual([
|
||||
[20, 1],
|
||||
[10, 2]
|
||||
]);
|
||||
});
|
||||
|
||||
it('resolves the queue head to the complete official record', async () => {
|
||||
const official = {
|
||||
firstName: 'Alex',
|
||||
lastName: 'Smith',
|
||||
country: 'GB',
|
||||
gender: 'M'
|
||||
};
|
||||
const id = await db.umpires.add(official);
|
||||
await service.add(id);
|
||||
expect(await service.getCurrentUmpire()).toEqual({ ...official, id });
|
||||
});
|
||||
|
||||
it('returns undefined for an empty queue or a missing roster record', async () => {
|
||||
expect(await service.getCurrentUmpire()).toBeUndefined();
|
||||
await service.add(999);
|
||||
expect(await service.getCurrentUmpire()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('updates only the selected record order', async () => {
|
||||
const id = await service.add(10);
|
||||
await service.add(20);
|
||||
await service.updateOrder(id, 5);
|
||||
expect(await queue()).toEqual([
|
||||
[20, 2],
|
||||
[10, 5]
|
||||
]);
|
||||
});
|
||||
|
||||
it('clears the queue and restarts ordering at one', async () => {
|
||||
await seed();
|
||||
await service.clear();
|
||||
expect(await queue()).toEqual([]);
|
||||
await service.add(40);
|
||||
expect(await queue()).toEqual([[40, 1]]);
|
||||
});
|
||||
});
|
||||
@@ -1,18 +1,245 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { signal } from '@angular/core';
|
||||
import { AlertController } from '@ionic/angular/standalone';
|
||||
import { CourtServiceJudge, CourtUmpire, Settings, Umpire } from 'db';
|
||||
import { Tab1Page } from './tab1.page';
|
||||
import { SettingsService } from '../services/settings-service';
|
||||
import { UmpireService } from '../services/umpire.service';
|
||||
import { WaitingUmpiresService } from '../services/waiting-umpires.service';
|
||||
import { WaitingServiceJudgesService } from '../services/waiting-service-judges.service';
|
||||
import { CourtUmpireService } from '../services/court.umpire.service';
|
||||
import { CourtServiceJudgeService } from '../services/court.service.judge.service';
|
||||
|
||||
describe('Tab1Page', () => {
|
||||
// Keep page tests independent of IndexedDB and test the public court actions.
|
||||
describe('Tab1Page court rotation', () => {
|
||||
let component: Tab1Page;
|
||||
let fixture: ComponentFixture<Tab1Page>;
|
||||
const official = (id: number): Umpire => ({
|
||||
id,
|
||||
firstName: `Official ${id}`,
|
||||
lastName: 'Smith',
|
||||
country: 'GB',
|
||||
gender: 'M'
|
||||
});
|
||||
const settings = signal<Settings>({
|
||||
id: 1,
|
||||
numberOfCourts: 3,
|
||||
withServiceJudge: true,
|
||||
showAlert: false
|
||||
});
|
||||
const umpires = signal<Umpire[]>([]);
|
||||
const courtUmpires = signal<CourtUmpire[]>([]);
|
||||
const courtJudges = signal<CourtServiceJudge[]>([]);
|
||||
let waitingUmpire: jasmine.SpyObj<WaitingUmpiresService>;
|
||||
let waitingJudge: jasmine.SpyObj<WaitingServiceJudgesService>;
|
||||
let umpireCourt: jasmine.SpyObj<CourtUmpireService>;
|
||||
let judgeCourt: jasmine.SpyObj<CourtServiceJudgeService>;
|
||||
let alerts: jasmine.SpyObj<AlertController>;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
settings.set({
|
||||
id: 1,
|
||||
numberOfCourts: 3,
|
||||
withServiceJudge: true,
|
||||
showAlert: false
|
||||
});
|
||||
umpires.set([
|
||||
official(1),
|
||||
official(2),
|
||||
official(3),
|
||||
official(4),
|
||||
official(5)
|
||||
]);
|
||||
courtUmpires.set([]);
|
||||
courtJudges.set([]);
|
||||
waitingUmpire = jasmine.createSpyObj(
|
||||
'WaitingUmpiresService',
|
||||
['getCurrentUmpire', 'add', 'removeByUmpireId'],
|
||||
{ waitingUmpires: signal([{ id: 1, umpireId: 1, order: 1 }]) }
|
||||
);
|
||||
waitingJudge = jasmine.createSpyObj(
|
||||
'WaitingServiceJudgesService',
|
||||
['getCurrentUmpire', 'add', 'removeByUmpireId'],
|
||||
{ waitingServiceJudges: signal([{ id: 1, serviceJudgeId: 2, order: 1 }]) }
|
||||
);
|
||||
umpireCourt = jasmine.createSpyObj(
|
||||
'CourtUmpireService',
|
||||
['save', 'removeByUmpireId'],
|
||||
{ umpires: courtUmpires }
|
||||
);
|
||||
judgeCourt = jasmine.createSpyObj(
|
||||
'CourtServiceJudgeService',
|
||||
['save', 'removeByUmpireId'],
|
||||
{ umpires: courtJudges }
|
||||
);
|
||||
alerts = jasmine.createSpyObj('AlertController', ['create']);
|
||||
waitingUmpire.getCurrentUmpire.and.resolveTo(official(1));
|
||||
waitingJudge.getCurrentUmpire.and.resolveTo(official(2));
|
||||
waitingUmpire.add.and.resolveTo(1);
|
||||
waitingJudge.add.and.resolveTo(1);
|
||||
umpireCourt.save.and.resolveTo(1);
|
||||
judgeCourt.save.and.resolveTo(1);
|
||||
waitingUmpire.removeByUmpireId.and.resolveTo();
|
||||
waitingJudge.removeByUmpireId.and.resolveTo();
|
||||
umpireCourt.removeByUmpireId.and.resolveTo();
|
||||
judgeCourt.removeByUmpireId.and.resolveTo();
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: SettingsService, useValue: { settings } },
|
||||
{ provide: UmpireService, useValue: { umpires } },
|
||||
{ provide: WaitingUmpiresService, useValue: waitingUmpire },
|
||||
{ provide: WaitingServiceJudgesService, useValue: waitingJudge },
|
||||
{ provide: CourtUmpireService, useValue: umpireCourt },
|
||||
{ provide: CourtServiceJudgeService, useValue: judgeCourt },
|
||||
{ provide: AlertController, useValue: alerts }
|
||||
]
|
||||
});
|
||||
fixture = TestBed.createComponent(Tab1Page);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
it('waits for confirmation before assigning officials', async () => {
|
||||
settings.update((value) => ({ ...value, showAlert: true }));
|
||||
const present = jasmine.createSpy('present').and.resolveTo();
|
||||
alerts.create.and.resolveTo({ present } as unknown as HTMLIonAlertElement);
|
||||
await component.showAddConfirmation(2);
|
||||
expect(present).toHaveBeenCalledTimes(1);
|
||||
expect(umpireCourt.save).not.toHaveBeenCalled();
|
||||
expect(judgeCourt.save).not.toHaveBeenCalled();
|
||||
const options = alerts.create.calls.mostRecent().args[0];
|
||||
const confirm = options?.buttons?.find(
|
||||
(button) => typeof button !== 'string' && button.role === 'confirm'
|
||||
);
|
||||
expect(confirm).toBeDefined();
|
||||
if (typeof confirm === 'object' && typeof confirm.handler === 'function') {
|
||||
confirm.handler(undefined);
|
||||
}
|
||||
await fixture.whenStable();
|
||||
expect(umpireCourt.save).toHaveBeenCalledOnceWith({
|
||||
courtNo: 2,
|
||||
umpireId: 1
|
||||
});
|
||||
expect(judgeCourt.save).toHaveBeenCalledOnceWith({
|
||||
courtNo: 2,
|
||||
umpireId: 2
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a lone umpire to the umpire queue after confirming rotation', async () => {
|
||||
settings.update((value) => ({
|
||||
...value,
|
||||
showAlert: true,
|
||||
withServiceJudge: false
|
||||
}));
|
||||
courtUmpires.set([{ id: 1, umpireId: 3, courtNo: 2 }]);
|
||||
const present = jasmine.createSpy('present').and.resolveTo();
|
||||
alerts.create.and.resolveTo({ present } as unknown as HTMLIonAlertElement);
|
||||
await component.showRemoveConfirmation(2);
|
||||
expect(umpireCourt.removeByUmpireId).not.toHaveBeenCalled();
|
||||
const options = alerts.create.calls.mostRecent().args[0];
|
||||
const confirm = options?.buttons?.find(
|
||||
(button) => typeof button !== 'string' && button.role === 'confirm'
|
||||
);
|
||||
expect(confirm).toBeDefined();
|
||||
if (typeof confirm === 'object' && typeof confirm.handler === 'function') {
|
||||
confirm.handler(undefined);
|
||||
}
|
||||
await fixture.whenStable();
|
||||
expect(umpireCourt.removeByUmpireId).toHaveBeenCalledOnceWith(3);
|
||||
expect(waitingUmpire.add).toHaveBeenCalledOnceWith(3);
|
||||
expect(waitingJudge.add).not.toHaveBeenCalled();
|
||||
expect(judgeCourt.removeByUmpireId).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('assigns both queue heads and removes them from their queues', async () => {
|
||||
await component.showAddConfirmation(3);
|
||||
await fixture.whenStable();
|
||||
expect(umpireCourt.save).toHaveBeenCalledOnceWith({
|
||||
courtNo: 3,
|
||||
umpireId: 1
|
||||
});
|
||||
expect(judgeCourt.save).toHaveBeenCalledOnceWith({
|
||||
courtNo: 3,
|
||||
umpireId: 2
|
||||
});
|
||||
expect(waitingUmpire.removeByUmpireId).toHaveBeenCalledOnceWith(1);
|
||||
expect(waitingJudge.removeByUmpireId).toHaveBeenCalledOnceWith(2);
|
||||
expect(alerts.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not assign either role when the required service judge is missing', async () => {
|
||||
waitingJudge.getCurrentUmpire.and.resolveTo(undefined);
|
||||
await component.showAddConfirmation(1);
|
||||
expect(umpireCourt.save).not.toHaveBeenCalled();
|
||||
expect(judgeCourt.save).not.toHaveBeenCalled();
|
||||
expect(waitingUmpire.removeByUmpireId).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not assign when the umpire queue is empty', async () => {
|
||||
waitingUmpire.getCurrentUmpire.and.resolveTo(undefined);
|
||||
await component.showAddConfirmation(1);
|
||||
expect(umpireCourt.save).not.toHaveBeenCalled();
|
||||
expect(judgeCourt.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('assigns only an umpire when service judges are disabled', async () => {
|
||||
settings.update((value) => ({ ...value, withServiceJudge: false }));
|
||||
await component.showAddConfirmation(2);
|
||||
await fixture.whenStable();
|
||||
expect(umpireCourt.save).toHaveBeenCalledOnceWith({
|
||||
courtNo: 2,
|
||||
umpireId: 1
|
||||
});
|
||||
expect(waitingUmpire.removeByUmpireId).toHaveBeenCalledOnceWith(1);
|
||||
expect(judgeCourt.save).not.toHaveBeenCalled();
|
||||
expect(waitingJudge.removeByUmpireId).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('swaps outgoing officials into the opposite role queues', async () => {
|
||||
courtUmpires.set([{ id: 1, umpireId: 3, courtNo: 2 }]);
|
||||
courtJudges.set([{ id: 1, umpireId: 4, courtNo: 2 }]);
|
||||
await component.showRemoveConfirmation(2);
|
||||
await fixture.whenStable();
|
||||
expect(umpireCourt.removeByUmpireId).toHaveBeenCalledOnceWith(3);
|
||||
expect(judgeCourt.removeByUmpireId).toHaveBeenCalledOnceWith(4);
|
||||
expect(waitingUmpire.add).toHaveBeenCalledOnceWith(4);
|
||||
expect(waitingJudge.add).toHaveBeenCalledOnceWith(3);
|
||||
});
|
||||
|
||||
it('leaves an incomplete court unchanged when service judges are required', async () => {
|
||||
courtUmpires.set([{ id: 1, umpireId: 3, courtNo: 2 }]);
|
||||
await component.showRemoveConfirmation(2);
|
||||
expect(umpireCourt.removeByUmpireId).not.toHaveBeenCalled();
|
||||
expect(waitingUmpire.add).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('derives rest from all four duty states and reacts to assignment changes', () => {
|
||||
courtUmpires.set([{ id: 1, umpireId: 3, courtNo: 2 }]);
|
||||
courtJudges.set([{ id: 1, umpireId: 4, courtNo: 2 }]);
|
||||
expect(component.onRest().map((item) => item.id)).toEqual([5]);
|
||||
courtJudges.set([]);
|
||||
expect(component.onRest().map((item) => item.id)).toEqual([4, 5]);
|
||||
});
|
||||
|
||||
it('ignores empty and stale court assignments in its court lookup', () => {
|
||||
courtUmpires.set([
|
||||
{ id: 1, umpireId: null, courtNo: 1 },
|
||||
{ id: 2, umpireId: 999, courtNo: 2 },
|
||||
{ id: 3, umpireId: 3, courtNo: 3 }
|
||||
]);
|
||||
expect([...component.umpireByCourt().entries()]).toEqual([
|
||||
[3, official(3)]
|
||||
]);
|
||||
});
|
||||
|
||||
it('updates court numbers and service judge availability from settings', () => {
|
||||
expect(component.courtIndexes()).toEqual([1, 2, 3]);
|
||||
settings.update((value) => ({
|
||||
...value,
|
||||
numberOfCourts: 1,
|
||||
withServiceJudge: false
|
||||
}));
|
||||
expect(component.courtIndexes()).toEqual([1]);
|
||||
expect(component.serviceJudgeEnabled()).toBeFalse();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user