S18 Added OR Tools rules for scheduling show
All checks were successful
Build, test and publish / verify (push) Successful in 6m12s
All checks were successful
Build, test and publish / verify (push) Successful in 6m12s
This commit is contained in:
88
agiledancers-fe/src/app/shared/schedule-editor.spec.ts
Normal file
88
agiledancers-fe/src/app/shared/schedule-editor.spec.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Show, DanceGroup } from '../core/api-models';
|
||||
import { SchoolApi } from '../core/school-api';
|
||||
import { ScheduleEditor } from './schedule-editor';
|
||||
|
||||
const groups: DanceGroup[] = [1, 2, 3].map((id) => ({
|
||||
id,
|
||||
category: `Group ${id}`,
|
||||
type: 'REGULAR',
|
||||
startAge: 0,
|
||||
endAge: 99,
|
||||
styles: [],
|
||||
dancerIds: [id],
|
||||
}));
|
||||
const show: Show = {
|
||||
id: 4,
|
||||
name: 'Show',
|
||||
preferredDayParts: 1,
|
||||
finalized: true,
|
||||
violations: [],
|
||||
appearances: {},
|
||||
dayParts: [
|
||||
{ date: '2027-01-01', type: 'MORNING', danceGroupIds: [1, 2] },
|
||||
{ date: '2027-01-02', type: 'MORNING', danceGroupIds: [3] },
|
||||
],
|
||||
};
|
||||
|
||||
describe('ScheduleEditor', () => {
|
||||
const api = { saveAssignments: vi.fn(), finalize: vi.fn() };
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
TestBed.configureTestingModule({ providers: [{ provide: SchoolApi, useValue: api }] });
|
||||
});
|
||||
function editor() {
|
||||
const fixture = TestBed.createComponent(ScheduleEditor);
|
||||
fixture.componentRef.setInput('show', show);
|
||||
fixture.componentRef.setInput('groups', groups);
|
||||
fixture.componentRef.setInput('schoolId', 7);
|
||||
fixture.componentInstance.ngOnInit();
|
||||
return fixture.componentInstance;
|
||||
}
|
||||
it('edits order and dayparts without changing the saved input', () => {
|
||||
const component = editor();
|
||||
component.reorder(0, 1, -1);
|
||||
component.move(0, 0, 1);
|
||||
component.add(0, 3);
|
||||
component.remove(1, 0);
|
||||
expect(component.assignments).toEqual([[1, 3], [2]]);
|
||||
expect(show.dayParts[0].danceGroupIds).toEqual([1, 2]);
|
||||
expect(component.dirty()).toBe(true);
|
||||
});
|
||||
it('saves invalid drafts and displays server violations without finalizing', async () => {
|
||||
const component = editor();
|
||||
component.remove(0, 0);
|
||||
const draft = { ...show, finalized: false, violations: ['Group 1 requires 1 dayparts.'] };
|
||||
api.saveAssignments.mockReturnValue(of(draft));
|
||||
await component.save();
|
||||
expect(api.saveAssignments).toHaveBeenCalledWith(7, 4, [[2], [3]]);
|
||||
expect(component.current()).toEqual(draft);
|
||||
expect(component.dirty()).toBe(false);
|
||||
expect(api.finalize).not.toHaveBeenCalled();
|
||||
});
|
||||
it('keeps unsaved edits when saving fails', async () => {
|
||||
const component = editor();
|
||||
component.remove(0, 0);
|
||||
api.saveAssignments.mockReturnValue(throwError(() => new HttpErrorResponse({ status: 0 })));
|
||||
await component.save();
|
||||
expect(component.assignments).toEqual([[2], [3]]);
|
||||
expect(component.dirty()).toBe(true);
|
||||
expect(component.error()).toContain('niet bereikbaar');
|
||||
expect(component.busy()).toBe(false);
|
||||
});
|
||||
it('finalizes through the server and reports a stale validation failure', async () => {
|
||||
const component = editor();
|
||||
api.finalize.mockReturnValue(of(show));
|
||||
await component.finalize();
|
||||
expect(component.current()?.finalized).toBe(true);
|
||||
api.finalize.mockReturnValue(
|
||||
throwError(
|
||||
() => new HttpErrorResponse({ status: 400, error: { message: 'Changing gap violated' } }),
|
||||
),
|
||||
);
|
||||
await component.finalize();
|
||||
expect(component.error()).toContain('Changing gap violated');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user