// DetachedRun model — the phase mapping + cancellable predicate that // drive the runs monitor's chip tone and the cancel-button visibility. import 'package:flutter_test/flutter_test.dart'; import 'package:chain_studio/data/hub.dart'; // The generated enum type isn't re-exported by the SDK's public // surface (only the message typedefs are), so build fixtures against // the generated file directly — test-only. import 'package:chain_client_sdk/src/generated/chain/v1/hub.pb.dart'; InvocationEntry _entry({ required String id, required int phaseValue, String flow = 'demo', String project = 'general', String step = '', String error = '', }) { final status = InvocationStatus() ..phase = InvocationStatus_Phase.valueOf(phaseValue)! ..currentStep = step ..startedAt = '2026-07-12T10:00:00Z' ..error = error; return InvocationEntry() ..invocationId = id ..flowName = flow ..project = project ..status = status; } void main() { test('maps each wire phase to the model phase', () { expect( DetachedRun.fromEntry(_entry(id: 'a', phaseValue: 1)).phase, DetachedPhase.pending, ); expect( DetachedRun.fromEntry(_entry(id: 'b', phaseValue: 2)).phase, DetachedPhase.running, ); expect( DetachedRun.fromEntry(_entry(id: 'c', phaseValue: 3)).phase, DetachedPhase.succeeded, ); expect( DetachedRun.fromEntry(_entry(id: 'd', phaseValue: 4)).phase, DetachedPhase.failed, ); expect( DetachedRun.fromEntry(_entry(id: 'e', phaseValue: 5)).phase, DetachedPhase.cancelled, ); expect( DetachedRun.fromEntry(_entry(id: 'f', phaseValue: 0)).phase, DetachedPhase.unknown, ); }); test('only pending and running runs are cancellable', () { expect( DetachedRun.fromEntry(_entry(id: 'a', phaseValue: 1)).isCancellable, isTrue, ); expect( DetachedRun.fromEntry(_entry(id: 'b', phaseValue: 2)).isCancellable, isTrue, ); for (final terminal in [3, 4, 5]) { expect( DetachedRun.fromEntry(_entry(id: 'x', phaseValue: terminal)) .isCancellable, isFalse, ); } }); test('carries flow name, project, step and error through', () { final run = DetachedRun.fromEntry( _entry( id: 'inv-1', phaseValue: 4, flow: 'intake', project: 'client-a', step: 'extract', error: 'boom', ), ); expect(run.id, 'inv-1'); expect(run.flowName, 'intake'); expect(run.project, 'client-a'); expect(run.currentStep, 'extract'); expect(run.error, 'boom'); expect(run.startedAt, isNotNull); }); }