mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-15 09:30:59 +01:00
Flutter 3.50 deprecates package:flutter/material.dart for the material_ui package; its ThemeData is a different type, so apps on 3.50 need the theme builders to return material_ui's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
145 lines
4.5 KiB
Dart
145 lines
4.5 KiB
Dart
import 'package:design_system/design_system.dart';
|
|
import 'package:material_ui/material_ui.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
group('AppSpacing', () {
|
|
test('is a 4px-based scale in ascending order', () {
|
|
const scale = [
|
|
AppSpacing.xs,
|
|
AppSpacing.sm,
|
|
AppSpacing.md,
|
|
AppSpacing.lg,
|
|
AppSpacing.xl,
|
|
AppSpacing.xxl,
|
|
];
|
|
expect(scale, [4.0, 8.0, 16.0, 24.0, 32.0, 48.0]);
|
|
for (final step in scale) {
|
|
expect(step % 4, 0, reason: '$step is off the 4px grid');
|
|
}
|
|
});
|
|
});
|
|
|
|
group('AppRadius', () {
|
|
test('matches the frozen scale', () {
|
|
expect([AppRadius.sm, AppRadius.md, AppRadius.lg], [8.0, 12.0, 16.0]);
|
|
});
|
|
});
|
|
|
|
group('AppTextSize', () {
|
|
test('matches the frozen scale', () {
|
|
expect(
|
|
[
|
|
AppTextSize.caption,
|
|
AppTextSize.label,
|
|
AppTextSize.body,
|
|
AppTextSize.subtitle,
|
|
AppTextSize.title,
|
|
AppTextSize.display,
|
|
],
|
|
[12.0, 14.0, 16.0, 20.0, 24.0, 32.0],
|
|
);
|
|
});
|
|
|
|
test('body is the reading floor', () {
|
|
expect(AppTextSize.caption, lessThan(AppTextSize.body));
|
|
expect(AppTextSize.label, lessThan(AppTextSize.body));
|
|
});
|
|
});
|
|
|
|
group('AppPalette', () {
|
|
test('matches the frozen token table', () {
|
|
expect(AppPalette.ink, const Color(0xFF211D1B));
|
|
expect(AppPalette.inkRaised1, const Color(0xFF2B2624));
|
|
expect(AppPalette.inkRaised2, const Color(0xFF38312E));
|
|
expect(AppPalette.lineDark, const Color(0xFF463E3A));
|
|
expect(AppPalette.textOnDark, const Color(0xFFECEAE9));
|
|
expect(AppPalette.mutedOnDark, const Color(0xFFAAA09A));
|
|
expect(AppPalette.paper, const Color(0xFFF6F4F3));
|
|
expect(AppPalette.paperRaised, const Color(0xFFFCFBFB));
|
|
expect(AppPalette.lineLight, const Color(0xFFE0DAD7));
|
|
expect(AppPalette.mutedOnLight, const Color(0xFF70625B));
|
|
expect(AppPalette.accent, const Color(0xFFB8862E));
|
|
expect(AppPalette.success, const Color(0xFF8A9A3C));
|
|
expect(AppPalette.warning, const Color(0xFFE0A63C));
|
|
expect(AppPalette.danger, const Color(0xFFE2585F));
|
|
});
|
|
|
|
test(
|
|
'reuses ink for text-on-light and on-fill, as the table specifies',
|
|
() {
|
|
expect(AppPalette.textOnLight, AppPalette.ink);
|
|
expect(AppPalette.onFill, AppPalette.ink);
|
|
},
|
|
);
|
|
|
|
test('has one accent hue: info mirrors it', () {
|
|
expect(AppPalette.info, AppPalette.accent);
|
|
});
|
|
});
|
|
|
|
test('kProseMaxWidth caps line length', () {
|
|
expect(kProseMaxWidth, 640.0);
|
|
});
|
|
|
|
group('AppDuration', () {
|
|
test('matches the frozen scale, ascending', () {
|
|
const scale = [
|
|
AppDuration.instant,
|
|
AppDuration.fast,
|
|
AppDuration.base,
|
|
AppDuration.slow,
|
|
];
|
|
expect(scale.map((d) => d.inMilliseconds), [0, 120, 200, 320]);
|
|
for (var i = 1; i < scale.length; i++) {
|
|
expect(
|
|
scale[i] > scale[i - 1],
|
|
isTrue,
|
|
reason: 'step $i is not longer than the one before it',
|
|
);
|
|
}
|
|
});
|
|
|
|
test('instant is the zero the reduced-motion contract collapses to', () {
|
|
expect(AppDuration.instant, Duration.zero);
|
|
});
|
|
|
|
test(
|
|
'stays within the perceptible band: nothing over the 320ms ceiling',
|
|
() {
|
|
expect(AppDuration.slow.inMilliseconds, lessThanOrEqualTo(350));
|
|
expect(AppDuration.fast.inMilliseconds, greaterThanOrEqualTo(100));
|
|
},
|
|
);
|
|
});
|
|
|
|
group('AppCurve', () {
|
|
const curves = {
|
|
'standard': AppCurve.standard,
|
|
'decelerate': AppCurve.decelerate,
|
|
'accelerate': AppCurve.accelerate,
|
|
};
|
|
|
|
test('every curve is anchored at both ends', () {
|
|
curves.forEach((name, curve) {
|
|
expect(curve.transform(0), closeTo(0, 1e-6), reason: '$name at t=0');
|
|
expect(curve.transform(1), closeTo(1, 1e-6), reason: '$name at t=1');
|
|
});
|
|
});
|
|
|
|
test('matches the frozen control points', () {
|
|
expect(AppCurve.standard, const Cubic(0.2, 0, 0, 1));
|
|
expect(AppCurve.decelerate, const Cubic(0, 0, 0, 1));
|
|
expect(AppCurve.accelerate, const Cubic(0.3, 0, 1, 1));
|
|
});
|
|
|
|
test('decelerate leads and accelerate trails, as their names promise', () {
|
|
// Named for what they do at the END: decelerate has covered most of the
|
|
// distance by the midpoint (it is settling), accelerate has covered
|
|
// little (it is still winding up).
|
|
expect(AppCurve.decelerate.transform(0.5), greaterThan(0.5));
|
|
expect(AppCurve.accelerate.transform(0.5), lessThan(0.5));
|
|
});
|
|
});
|
|
}
|