89 lines
2.9 KiB
JavaScript
89 lines
2.9 KiB
JavaScript
|
|
/**
|
||
|
|
* Property-Based Test: Section Header Count Accuracy
|
||
|
|
*
|
||
|
|
* Feature: queue-collapsible-sections, Property 4: Section Header Count Accuracy
|
||
|
|
* **Validates: Requirements 3.1, 3.2**
|
||
|
|
*
|
||
|
|
* For every section in the grouped output, the items array length equals the count
|
||
|
|
* that would be displayed in the header. The sum of all section item counts equals
|
||
|
|
* the total input array length.
|
||
|
|
*/
|
||
|
|
import fc from 'fast-check';
|
||
|
|
|
||
|
|
// Replicate the grouping logic inline (utility file not yet extracted)
|
||
|
|
function groupQueueItems(visibleItems) {
|
||
|
|
const INVENTORY_TYPES = new Set(['CARD', 'GRANITE', 'DECOM']);
|
||
|
|
const inventoryItems = [];
|
||
|
|
const vendorMap = new Map();
|
||
|
|
for (const item of visibleItems) {
|
||
|
|
if (INVENTORY_TYPES.has(item.workflow_type)) {
|
||
|
|
inventoryItems.push(item);
|
||
|
|
} else {
|
||
|
|
const vendor = item.vendor?.trim() || 'Unknown';
|
||
|
|
if (!vendorMap.has(vendor)) vendorMap.set(vendor, []);
|
||
|
|
vendorMap.get(vendor).push(item);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const sections = [];
|
||
|
|
if (inventoryItems.length > 0) {
|
||
|
|
sections.push({ key: 'inventory', label: 'Inventory', type: 'inventory', items: inventoryItems });
|
||
|
|
}
|
||
|
|
const sortedVendors = [...vendorMap.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
||
|
|
for (const [vendor, items] of sortedVendors) {
|
||
|
|
sections.push({ key: `vendor:${vendor}`, label: vendor, type: 'vendor', items });
|
||
|
|
}
|
||
|
|
return sections;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Generator for queue items with realistic workflow types and vendor names
|
||
|
|
const workflowTypeArb = fc.constantFrom('CARD', 'GRANITE', 'DECOM', 'FP', 'Archer');
|
||
|
|
const vendorArb = fc.oneof(
|
||
|
|
fc.constantFrom('Microsoft', 'Adobe', 'Cisco', 'Oracle', 'VMware', 'Apple'),
|
||
|
|
fc.constant(''),
|
||
|
|
fc.constant(null),
|
||
|
|
fc.constant(undefined)
|
||
|
|
);
|
||
|
|
|
||
|
|
const queueItemArb = fc.record({
|
||
|
|
id: fc.uuid(),
|
||
|
|
workflow_type: workflowTypeArb,
|
||
|
|
vendor: vendorArb,
|
||
|
|
hostname: fc.string({ minLength: 1, maxLength: 20 }),
|
||
|
|
status: fc.constant('pending'),
|
||
|
|
});
|
||
|
|
|
||
|
|
const queueItemsArb = fc.array(queueItemArb, { minLength: 1, maxLength: 50 });
|
||
|
|
|
||
|
|
describe('Queue Grouping — Property 4: Section Header Count Accuracy', () => {
|
||
|
|
it('each section items.length is a positive integer (the displayed count)', () => {
|
||
|
|
fc.assert(
|
||
|
|
fc.property(queueItemsArb, (items) => {
|
||
|
|
const sections = groupQueueItems(items);
|
||
|
|
|
||
|
|
for (const section of sections) {
|
||
|
|
// items.length is the count that would be displayed in the header
|
||
|
|
expect(Number.isInteger(section.items.length)).toBe(true);
|
||
|
|
expect(section.items.length).toBeGreaterThan(0);
|
||
|
|
}
|
||
|
|
}),
|
||
|
|
{ numRuns: 200 }
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('sum of all section item counts equals total input array length', () => {
|
||
|
|
fc.assert(
|
||
|
|
fc.property(queueItemsArb, (items) => {
|
||
|
|
const sections = groupQueueItems(items);
|
||
|
|
|
||
|
|
const totalItemsInSections = sections.reduce(
|
||
|
|
(sum, section) => sum + section.items.length,
|
||
|
|
0
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(totalItemsInSections).toBe(items.length);
|
||
|
|
}),
|
||
|
|
{ numRuns: 200 }
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|