fix(chat): propagate empty draft on target swap and dispose
Oracle re-review on PR #30 flagged that _ChatDetailViewState only called onDraftChanged when _textCtl.text was non-empty. The empty case is load-bearing: if the user restored a saved draft, deleted the text, then switched target (or closed the panel), the parent's draft map kept the stale entry and resurrected it on the next swap. Fix: call onDraftChanged unconditionally in both didUpdateWidget (target change) and dispose (tear-down), so the parent map learns when a draft is now empty. Adds a regression test exercising the restore-clear-swap sequence.
This commit is contained in:
@@ -133,4 +133,69 @@ void main() {
|
||||
'server draft',
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'chat detail propagates empty draft when the user clears it before switching target',
|
||||
(tester) async {
|
||||
// Regression: previously, _ChatDetailViewState only emitted
|
||||
// onDraftChanged when the text was non-empty. If the user
|
||||
// restored a saved draft, deleted it, then switched target,
|
||||
// the stale entry stayed in the parent's draft map and
|
||||
// resurrected on the next target swap.
|
||||
String? savedDraft = 'sentinel-unset';
|
||||
final messages = <ChatEntry>[];
|
||||
|
||||
Widget detail({
|
||||
required rust.BridgeMessageTarget target,
|
||||
required String? restoredDraft,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
localizationsDelegates: AppL10n.localizationsDelegates,
|
||||
supportedLocales: AppL10n.supportedLocales,
|
||||
home: Scaffold(
|
||||
body: ChatDetailView(
|
||||
messages: messages,
|
||||
snapshot: snapshot(),
|
||||
target: target,
|
||||
clientName: '',
|
||||
currentChannelId: BigInt.from(10),
|
||||
channelName: 'Lobby',
|
||||
restoredDraft: restoredDraft,
|
||||
onDraftChanged: (text) => savedDraft = text,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(
|
||||
detail(
|
||||
target: const rust.BridgeMessageTarget.channel(),
|
||||
restoredDraft: 'previously saved channel draft',
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
tester.widget<TextField>(find.byType(TextField)).controller!.text,
|
||||
'previously saved channel draft',
|
||||
);
|
||||
|
||||
// User clears the field, then switches target.
|
||||
await tester.enterText(find.byType(TextField), '');
|
||||
await tester.pumpWidget(
|
||||
detail(
|
||||
target: const rust.BridgeMessageTarget.server(),
|
||||
restoredDraft: null,
|
||||
),
|
||||
);
|
||||
|
||||
// The empty string MUST reach the parent so the stale entry
|
||||
// is overwritten in the draft map. With the previous guarded
|
||||
// implementation, savedDraft would still hold the sentinel.
|
||||
expect(
|
||||
savedDraft,
|
||||
'',
|
||||
reason: 'empty draft must overwrite stale entry on target swap',
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user