1- import { describe , it , expect , vi , beforeEach } from "vitest" ;
1+ import { describe , it , expect , vi } from "vitest" ;
22import type { LiveStatusMap , StatusRow } from "@/lib/live-status" ;
33import type { Integration , Feature } from "@/lib/registry" ;
44
@@ -10,62 +10,27 @@ vi.mock("@/lib/registry", () => ({
1010 getFeatureCategories : vi . fn ( ( ) => [ ] ) ,
1111} ) ) ;
1212
13- // Mock live-status module before importing the function under test
14- vi . mock ( "@/lib/live-status" , async ( ) => {
15- const actual =
16- await vi . importActual < typeof import ( "@/lib/live-status" ) > (
17- "@/lib/live-status" ,
18- ) ;
19- return {
20- ...actual ,
21- keyFor : vi . fn ( actual . keyFor ) ,
22- resolveCell : vi . fn ( ) ,
23- } ;
24- } ) ;
25-
2613import { computeColumnTallyDetail } from "@/components/feature-grid" ;
27- import { keyFor , resolveCell } from "@/lib/live-status" ;
28- import type { CellState , BadgeRender } from "@/lib/live-status" ;
29-
30- const mockedResolveCell = vi . mocked ( resolveCell ) ;
3114
3215/* ------------------------------------------------------------------ */
3316/* Helpers */
3417/* ------------------------------------------------------------------ */
3518
36- function makeRow ( overrides : Partial < StatusRow > = { } ) : StatusRow {
19+ function makeRow (
20+ key : string ,
21+ dimension : string ,
22+ state : StatusRow [ "state" ] ,
23+ ) : StatusRow {
3724 return {
38- id : "row-1" ,
39- key : "health:test-slug" ,
40- dimension : "health" ,
41- state : "green" ,
25+ id : key ,
26+ key,
27+ dimension,
28+ state,
4229 signal : null ,
4330 observed_at : "2026-04-28T00:00:00Z" ,
4431 transitioned_at : "2026-04-28T00:00:00Z" ,
4532 fail_count : 0 ,
4633 first_failure_at : null ,
47- ...overrides ,
48- } ;
49- }
50-
51- function makeBadge ( tone : string ) : BadgeRender {
52- return {
53- tone : tone as BadgeRender [ "tone" ] ,
54- label : tone ,
55- tooltip : "" ,
56- row : null ,
57- } ;
58- }
59-
60- function makeCellState ( e2eTone : string ) : CellState {
61- return {
62- e2e : makeBadge ( e2eTone ) ,
63- smoke : makeBadge ( "gray" ) ,
64- health : makeBadge ( "gray" ) ,
65- d2 : makeBadge ( "gray" ) ,
66- d5 : makeBadge ( "gray" ) ,
67- d6 : makeBadge ( "gray" ) ,
68- rollup : e2eTone as CellState [ "rollup" ] ,
6934 } ;
7035}
7136
@@ -100,10 +65,6 @@ function makeFeature(id: string, name: string): Feature {
10065/* ------------------------------------------------------------------ */
10166
10267describe ( "computeColumnTallyDetail" , ( ) => {
103- beforeEach ( ( ) => {
104- vi . clearAllMocks ( ) ;
105- } ) ;
106-
10768 it ( "returns unknown: true with empty arrays when connection is error" , ( ) => {
10869 const integration = makeIntegration ( "test-int" , [ "feat-1" ] ) ;
10970 const features = [ makeFeature ( "feat-1" , "Feature 1" ) ] ;
@@ -122,27 +83,21 @@ describe("computeColumnTallyDetail", () => {
12283 red : [ ] ,
12384 unknown : true ,
12485 } ) ;
125- // resolveCell should NOT be called when connection is error
126- expect ( mockedResolveCell ) . not . toHaveBeenCalled ( ) ;
12786 } ) ;
12887
129- it ( "collects health green + 1 e2e green + 1 e2e red " , ( ) => {
88+ it ( "green D3 cells land in green bucket " , ( ) => {
13089 const integration = makeIntegration ( "my-int" , [ "feat-a" , "feat-b" ] ) ;
13190 const features = [
13291 makeFeature ( "feat-a" , "Feature A" ) ,
13392 makeFeature ( "feat-b" , "Feature B" ) ,
13493 ] ;
13594
136- const healthKey = keyFor ( "health" , "my-int" ) ;
95+ // Both features have green D3 → achievedDepth=3, ceilingDepth=3 → green chip
13796 const liveStatus : LiveStatusMap = new Map ( [
138- [ healthKey , makeRow ( { key : healthKey , state : "green" } ) ] ,
97+ [ "e2e:my-int/feat-a" , makeRow ( "e2e:my-int/feat-a" , "e2e" , "green" ) ] ,
98+ [ "e2e:my-int/feat-b" , makeRow ( "e2e:my-int/feat-b" , "e2e" , "green" ) ] ,
13999 ] ) ;
140100
141- // feat-a e2e → green, feat-b e2e → red
142- mockedResolveCell
143- . mockReturnValueOnce ( makeCellState ( "green" ) )
144- . mockReturnValueOnce ( makeCellState ( "red" ) ) ;
145-
146101 const result = computeColumnTallyDetail (
147102 integration ,
148103 features ,
@@ -152,27 +107,26 @@ describe("computeColumnTallyDetail", () => {
152107
153108 expect ( result . unknown ) . toBe ( false ) ;
154109 expect ( result . green ) . toEqual ( [
155- { label : "Health (Up)" , dimension : "health" } ,
156110 { label : "Feature A" , dimension : "e2e" , featureId : "feat-a" } ,
157- ] ) ;
158- expect ( result . red ) . toEqual ( [
159111 { label : "Feature B" , dimension : "e2e" , featureId : "feat-b" } ,
160112 ] ) ;
161113 expect ( result . amber ) . toEqual ( [ ] ) ;
114+ expect ( result . red ) . toEqual ( [ ] ) ;
162115 } ) ;
163116
164- it ( "collects amber e2e features when no health data exists " , ( ) => {
165- const integration = makeIntegration ( "no-health " , [ "feat-x " , "feat-y " ] ) ;
117+ it ( "red D3 cells are gray (achievedDepth=0) and excluded " , ( ) => {
118+ const integration = makeIntegration ( "my-int " , [ "feat-a " , "feat-b " ] ) ;
166119 const features = [
167- makeFeature ( "feat-x " , "Feature X " ) ,
168- makeFeature ( "feat-y " , "Feature Y " ) ,
120+ makeFeature ( "feat-a " , "Feature A " ) ,
121+ makeFeature ( "feat-b " , "Feature B " ) ,
169122 ] ;
170- const liveStatus : LiveStatusMap = new Map ( ) ;
171123
172- // Both features → amber
173- mockedResolveCell
174- . mockReturnValueOnce ( makeCellState ( "amber" ) )
175- . mockReturnValueOnce ( makeCellState ( "amber" ) ) ;
124+ // feat-a: D3=red → achievedDepth=0, ceilingDepth=3 → gray (skipped)
125+ // feat-b: D3=green → green chip
126+ const liveStatus : LiveStatusMap = new Map ( [
127+ [ "e2e:my-int/feat-a" , makeRow ( "e2e:my-int/feat-a" , "e2e" , "red" ) ] ,
128+ [ "e2e:my-int/feat-b" , makeRow ( "e2e:my-int/feat-b" , "e2e" , "green" ) ] ,
129+ ] ) ;
176130
177131 const result = computeColumnTallyDetail (
178132 integration ,
@@ -182,24 +136,24 @@ describe("computeColumnTallyDetail", () => {
182136 ) ;
183137
184138 expect ( result . unknown ) . toBe ( false ) ;
185- expect ( result . green ) . toEqual ( [ ] ) ;
186- expect ( result . red ) . toEqual ( [ ] ) ;
187- expect ( result . amber ) . toEqual ( [
188- { label : "Feature X" , dimension : "e2e" , featureId : "feat-x" } ,
189- { label : "Feature Y" , dimension : "e2e" , featureId : "feat-y" } ,
139+ expect ( result . green ) . toEqual ( [
140+ { label : "Feature B" , dimension : "e2e" , featureId : "feat-b" } ,
190141 ] ) ;
142+ expect ( result . amber ) . toEqual ( [ ] ) ;
143+ expect ( result . red ) . toEqual ( [ ] ) ;
191144 } ) ;
192145
193- it ( "skips features that have no matching demo " , ( ) => {
146+ it ( "features without demos are gray (unwired) and excluded " , ( ) => {
194147 // Integration only has demo for feat-1, not feat-2
195148 const integration = makeIntegration ( "partial" , [ "feat-1" ] ) ;
196149 const features = [
197150 makeFeature ( "feat-1" , "Feature 1" ) ,
198151 makeFeature ( "feat-2" , "Feature 2" ) ,
199152 ] ;
200- const liveStatus : LiveStatusMap = new Map ( ) ;
201153
202- mockedResolveCell . mockReturnValueOnce ( makeCellState ( "green" ) ) ;
154+ const liveStatus : LiveStatusMap = new Map ( [
155+ [ "e2e:partial/feat-1" , makeRow ( "e2e:partial/feat-1" , "e2e" , "green" ) ] ,
156+ ] ) ;
203157
204158 const result = computeColumnTallyDetail (
205159 integration ,
@@ -209,23 +163,20 @@ describe("computeColumnTallyDetail", () => {
209163 ) ;
210164
211165 expect ( result . unknown ) . toBe ( false ) ;
212- // Only feat-1 appears (has a demo); feat-2 is absent
166+ // Only feat-1 appears (has a demo); feat-2 is unwired → gray → excluded
213167 expect ( result . green ) . toEqual ( [
214168 { label : "Feature 1" , dimension : "e2e" , featureId : "feat-1" } ,
215169 ] ) ;
216170 expect ( result . amber ) . toEqual ( [ ] ) ;
217171 expect ( result . red ) . toEqual ( [ ] ) ;
218- // resolveCell was only called once (for feat-1)
219- expect ( mockedResolveCell ) . toHaveBeenCalledTimes ( 1 ) ;
220172 } ) ;
221173
222- it ( "routes degraded health to amber bucket " , ( ) => {
223- const integration = makeIntegration ( "degraded-int " , [ ] ) ;
174+ it ( "health-only data produces no tally items ( health not in cell model) " , ( ) => {
175+ const integration = makeIntegration ( "health-only " , [ ] ) ;
224176 const features : Feature [ ] = [ ] ;
225177
226- const healthKey = keyFor ( "health" , "degraded-int" ) ;
227178 const liveStatus : LiveStatusMap = new Map ( [
228- [ healthKey , makeRow ( { key : healthKey , state : "degraded" } ) ] ,
179+ [ "health:health-only" , makeRow ( "health:health-only" , "health" , "red" ) ] ,
229180 ] ) ;
230181
231182 const result = computeColumnTallyDetail (
@@ -235,21 +186,26 @@ describe("computeColumnTallyDetail", () => {
235186 "live" ,
236187 ) ;
237188
238- expect ( result . amber ) . toEqual ( [
239- { label : "Health (Up)" , dimension : "health" } ,
240- ] ) ;
189+ // No features → no cells → nothing counted
241190 expect ( result . green ) . toEqual ( [ ] ) ;
191+ expect ( result . amber ) . toEqual ( [ ] ) ;
242192 expect ( result . red ) . toEqual ( [ ] ) ;
243193 expect ( result . unknown ) . toBe ( false ) ;
244194 } ) ;
245195
246- it ( "routes red health to red bucket" , ( ) => {
247- const integration = makeIntegration ( "red-int" , [ ] ) ;
248- const features : Feature [ ] = [ ] ;
196+ it ( "not_supported_features are gray and excluded" , ( ) => {
197+ const integration = {
198+ ...makeIntegration ( "ns-int" , [ "feat-a" , "feat-b" ] ) ,
199+ not_supported_features : [ "feat-b" ] ,
200+ } ;
201+ const features = [
202+ makeFeature ( "feat-a" , "Feature A" ) ,
203+ makeFeature ( "feat-b" , "Feature B" ) ,
204+ ] ;
249205
250- const healthKey = keyFor ( "health" , "red-int" ) ;
251206 const liveStatus : LiveStatusMap = new Map ( [
252- [ healthKey , makeRow ( { key : healthKey , state : "red" } ) ] ,
207+ [ "e2e:ns-int/feat-a" , makeRow ( "e2e:ns-int/feat-a" , "e2e" , "green" ) ] ,
208+ [ "e2e:ns-int/feat-b" , makeRow ( "e2e:ns-int/feat-b" , "e2e" , "green" ) ] ,
253209 ] ) ;
254210
255211 const result = computeColumnTallyDetail (
@@ -259,9 +215,12 @@ describe("computeColumnTallyDetail", () => {
259215 "live" ,
260216 ) ;
261217
262- expect ( result . red ) . toEqual ( [ { label : "Health (Up)" , dimension : "health" } ] ) ;
263- expect ( result . green ) . toEqual ( [ ] ) ;
264- expect ( result . amber ) . toEqual ( [ ] ) ;
265218 expect ( result . unknown ) . toBe ( false ) ;
219+ // feat-a: green; feat-b: unsupported → gray → excluded
220+ expect ( result . green ) . toEqual ( [
221+ { label : "Feature A" , dimension : "e2e" , featureId : "feat-a" } ,
222+ ] ) ;
223+ expect ( result . amber ) . toEqual ( [ ] ) ;
224+ expect ( result . red ) . toEqual ( [ ] ) ;
266225 } ) ;
267226} ) ;
0 commit comments