import { describe, expect, it } from 'vitest'; import { defaultProject, rectangle } from '../src/lib/defaults'; import { flooringCuts, groupFlooringCuts, groupSkirtingCuts, skirtingCuts, } from '../src/lib/cut-list'; import { planFlooring } from '../src/lib/flooring'; import { planSkirting } from '../src/lib/skirting'; import type { FlooringPiece, FlooringPlan } from '../src/lib/types'; function piece(id: string, stockId: string, changes: Partial = {}): FlooringPiece { const length = changes.length ?? 600; const width = changes.width ?? 190; return { id, roomId: 'room-1', row: 1, polygon: [], length, width, blankLength: length, blankWidth: width, stockId, reused: false, cut: true, shaped: false, template: [ { x: 0, y: 0 }, { x: length, y: 0 }, { x: length, y: width }, { x: 0, y: width }, ], factoryLeft: false, factoryRight: false, ripEdge: null, ...changes, }; } function plan(pieces: FlooringPiece[]): FlooringPlan { return { pieces, rows: [], stocks: ['B1', 'B2', 'B3'].map((id) => ({ id, pieceIds: pieces.filter((p) => p.stockId === id).map((p) => p.id), remaining: 0, })), boardCount: 3, cuts: 0, wasteArea: 0, wastePercent: 0, reusedCount: 0, coveredArea: 0, issues: [], }; } describe('cuts grouped by purchased board', () => { it('keeps different cuts and cross-room offcuts together, separating identical cuts from different boards', () => { const source = plan([ piece('F1', 'B2'), piece('F2', 'B1'), piece('F3', 'B2', { roomId: 'room-2', row: 4, length: 397, reused: true }), piece('FU1', 'B3', { length: 1200, cut: false }), ]); const before = structuredClone(source); const groups = groupFlooringCuts(source); expect(groups.map((group) => group.map((p) => p.id))).toEqual([['F2'], ['F1', 'F3']]); expect(source).toEqual(before); expect(groupFlooringCuts(source)).toEqual(groups); }); it('includes ready-to-use offcuts in their original board group', () => { const groups = groupFlooringCuts( plan([piece('F1', 'B1'), piece('F2', 'B1', { cut: false, reused: true })]), ); expect(groups.map((group) => group.map((p) => p.id))).toEqual([['F1', 'F2']]); }); it('includes every flooring and skirting cut once in stock order across multiple rooms', () => { const project = defaultProject(); project.rooms.push(rectangle('room-2', 'Study', 3200, 3100)); const floor = planFlooring(project.rooms, project.flooring, project.tolerance); const skirt = planSkirting(project.rooms, project.skirting, project.tolerance); for (const [groups, pieces, stocks] of [ [groupFlooringCuts(floor), flooringCuts(floor), floor.stocks], [groupSkirtingCuts(skirt), skirtingCuts(skirt), skirt.stocks], ] as const) { expect( groups .flat() .map((p) => p.id) .sort(), ).toEqual(pieces.map((p) => p.id).sort()); expect(new Set(groups.flat().map((p) => p.id)).size).toBe(pieces.length); const used = new Set(pieces.map((p) => p.stockId)); expect(groups.map((group) => group[0].stockId)).toEqual( stocks.filter((s) => used.has(s.id)).map((s) => s.id), ); for (const group of groups) expect(new Set(group.map((p) => p.stockId)).size).toBe(1); } expect( [...groupFlooringCuts(floor), ...groupSkirtingCuts(skirt)].some( (group) => new Set(group.map((p) => p.roomId)).size > 1, ), ).toBe(true); }); });