Files
sure/mobile/test/widgets/money_text_test.dart
ghost e38632632c feat(mobile): standardize money typography and semantic amount color (#2331)
* feat(mobile): standardize money typography and semantic amount color

Add a brightness-aware SureColors theme extension and a MoneyText/SureMoney
primitive (semantic success/destructive/subdued tokens + tabular figures for
column-aligned digits), then migrate the transaction lists and balance cards
off raw Colors.green/red/grey.

Step 2 of the mobile design-system sequence (#2235), after #2237's theme
foundation. Primitive-first: screens consume shared tokens/typography.

* fix: review feedback — brightness-aware token fallback, de-flake Setting tests, Pipelock localhost FP

- SureColors.of falls back to the palette matching the active brightness (not
  always light) when the extension is missing, so dark surfaces stay correct.
- Clear the rails-settings-cached cache before each test; its in-memory cache
  survives the per-test transaction rollback, leaking Setting.* across tests and
  flaking Settings::HostingsControllerTest (stale empty string vs nil).
  Full unit suite: 4952 runs, 0 failures.
- Suppress the localhost test-DB DATABASE_URL false positive with line-level
  `# pipelock:ignore` in ci.yml + llm-evals.yml instead of excluding whole files,
  so those workflows stay scanned for real secrets.
2026-06-14 21:37:30 +02:00

75 lines
2.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:sure_mobile/theme/sure_theme.dart';
import 'package:sure_mobile/theme/sure_tokens.dart';
import 'package:sure_mobile/widgets/money_text.dart';
void main() {
group('SureMoney.trendForAmount', () {
test('null amount is neutral', () {
expect(SureMoney.trendForAmount(null), MoneyTrend.neutral);
});
test('positive and zero are inflow, negative is outflow', () {
expect(SureMoney.trendForAmount(12.5), MoneyTrend.inflow);
expect(SureMoney.trendForAmount(0), MoneyTrend.inflow);
expect(SureMoney.trendForAmount(-3), MoneyTrend.outflow);
});
});
Future<BuildContext> pumpContext(WidgetTester tester, ThemeData theme) async {
late BuildContext captured;
await tester.pumpWidget(
MaterialApp(
theme: theme,
home: Builder(
builder: (context) {
captured = context;
return const SizedBox.shrink();
},
),
),
);
return captured;
}
group('SureMoney.color resolves design-system tokens', () {
testWidgets('light theme maps trends to success/destructive/subdued',
(tester) async {
final context = await pumpContext(tester, SureTheme.light);
expect(SureMoney.color(context, MoneyTrend.inflow),
SureTokens.light.success);
expect(SureMoney.color(context, MoneyTrend.outflow),
SureTokens.light.destructive);
expect(SureMoney.color(context, MoneyTrend.neutral),
SureTokens.light.textSubdued);
});
testWidgets('dark theme resolves the dark palette', (tester) async {
final context = await pumpContext(tester, SureTheme.dark);
expect(
SureMoney.color(context, MoneyTrend.inflow), SureTokens.dark.success);
expect(SureMoney.color(context, MoneyTrend.outflow),
SureTokens.dark.destructive);
});
});
group('MoneyText', () {
testWidgets('applies semantic color and tabular figures', (tester) async {
await tester.pumpWidget(
MaterialApp(
theme: SureTheme.light,
home: const Scaffold(
body: MoneyText('+\$10.00', trend: MoneyTrend.inflow),
),
),
);
final text = tester.widget<Text>(find.text('+\$10.00'));
expect(text.style?.color, SureTokens.light.success);
expect(text.style?.fontFeatures,
contains(const FontFeature.tabularFigures()));
});
});
}