line-class.test.ts
Language TypeScript5.3 KB118 lines
/*** Which order lines count as work this team owes.** Every order-line count on the board (the queue, `ourMove`, `atVendor`,* `waitingOnClient`, every person's workload) classifies each line with this* rule. Classifying on the order status alone makes the queue show a handful of* lines against a window holding hundreds.** Neither field alone is right, because they go stale in opposite directions,* and live Plinth data shows both:** - order status stale behind: an order sitting "On Press" with a product* line still in File Check is somebody's job today, and filtering on the* order hides it.* - product status stale ahead: the product row parks at its last value when* an order ships. Most design-stage product lines in a typical fortnight sit* on orders already shipped or delivered. Filtering on the product alone* resurrects them as open artwork, which "makes the team look behind when it* is not", the failure the board's own footer warns about.** So the rule takes both: ours when the product says ours and the order has not* moved past Part Dispatched.*/import { describe, expect, it } from 'vitest'import { classifyLine, isLineDesignQueue, isOrderPastFulfilment } from '../src/status-taxonomy.js'const line = (productStatus: string, orderStatus: string) => ({productStatus,productStatusId: null,orderStatus,orderStatusId: null,})describe('the product row says what the work is', () => {it('counts design work on an order that has already left for the vendor', () => {// The line an order-only rule hides. "On Press" is at-vendor at the order// level, so the whole line would vanish, including the artwork nobody had// done.expect(classifyLine(line('File Check', 'On Press'))).toBe('ours')expect(classifyLine(line('File Check', 'Cleared For Print'))).toBe('ours')})it('keeps a line waiting on the client out of the team’s column', () => {expect(classifyLine(line('Waiting On Files', 'On Press'))).toBe('client')expect(classifyLine(line('Proof With Client', 'Proof Out'))).toBe('client')})it('keeps a line at the vendor out of it too', () => {expect(classifyLine(line('Partner Dispatched', 'On Press'))).toBe('vendor')})})describe('the order says whether the work is still here', () => {it('drops a stale product row on an order that has shipped', () => {// The phantom a product-only rule would create: several of these in a// typical fortnight.expect(classifyLine(line('File Check', 'Dispatched'))).toBe('terminal')expect(classifyLine(line('File Check', 'Delivered'))).toBe('terminal')expect(classifyLine(line('Waiting On Files', 'Awaiting Collection'))).toBe('terminal')})it('treats Part Dispatched as still here (Sam’s cutoff, 2026-09-17)', () => {// The rule is "has not moved PAST Part Dispatched", so this one is in.expect(isOrderPastFulfilment('Part Dispatched')).toBe(false)expect(classifyLine(line('File Check', 'Part Dispatched'))).toBe('ours')// And the next one along is out.expect(isOrderPastFulfilment('Dispatched')).toBe(true)})it('drops cancelled and refunded orders, whatever the product row says', () => {for (const s of ['Cancelled', 'Refunded', 'Claim Settled']) {expect(classifyLine(line('File Check', s)), s).toBe('terminal')}})it('keeps a cancellation REQUEST, because that is a decision somebody owes', () => {// 'Cancel Requested' is classed 'ours' in the order catalog for// exactly this reason, and it is not past fulfilment.expect(isOrderPastFulfilment('Cancel Requested')).toBe(false)})})describe('the unknown direction', () => {it('lets a line through when the order status is one nobody has classified', () => {// Same direction as classifyProduct's unknown default: a status nobody has// seen yet should appear on the page and be noticed, not be filtered off it.expect(isOrderPastFulfilment('Some New Status Ops Added')).toBe(false)expect(classifyLine(line('File Check', 'Some New Status Ops Added'))).toBe('ours')})it('still counts an unknown PRODUCT status as ours, so it gets noticed', () => {expect(classifyLine(line('Some New Product Status', 'On Press'))).toBe('ours')})})describe('the design queue rides the same gate', () => {it('counts artwork on a live order and not on a shipped one', () => {expect(isLineDesignQueue(line('File Check', 'On Press'))).toBe(true)expect(isLineDesignQueue(line('File Check', 'Dispatched'))).toBe(false)})it('does not count a line that is not design work', () => {expect(isLineDesignQueue(line('Partner Dispatched', 'On Press'))).toBe(false)})})describe('the two catalogs are not interchangeable', () => {it('reads the product name against the PRODUCT catalog', () => {// "Proof Out" exists only at order level. Putting it in the product field// (which the dashboard fixture did until this change) hits the// unknown-means-ours default and silently turns a client wait into team// workload. That is how every fixture line read as work for one commit.expect(classifyLine(line('Proof Out', 'Proof Out'))).toBe('ours')// Whereas the product catalog's name for the same wait classifies right.expect(classifyLine(line('Proof With Client', 'Proof Out'))).toBe('client')})})