Files
sharedinbox/test/widget/secure_email_webview_test.dart
T
Thomas SharedInboxandClaude Sonnet 4.6 a38691a760 fix(html-mail): force light color-scheme to prevent black-on-black in dark mode (#98)
HTML emails with black text became unreadable when viewed in dark mode
because the WebView inherited a dark background from the system theme.
Inject `color-scheme: light` CSS + meta tag so the WebView always renders
email content on a white background, regardless of the device theme.

Extracts `buildEmailHtml()` as a `@visibleForTesting` top-level function
and adds unit tests to cover the light-mode enforcement and CSP logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 21:01:57 +02:00

107 lines
3.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:sharedinbox/ui/widgets/secure_email_webview.dart';
void _expectLightMode(String html) {
expect(html, contains('color-scheme" content="light"'));
expect(html, contains('color-scheme: light'));
expect(html, contains('background-color: #ffffff'));
expect(html, contains('color: #000000'));
}
Widget _wrap(Widget child) => MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: Scaffold(body: child),
);
void main() {
group('buildEmailHtml', () {
test('forces light color-scheme to prevent black-on-black in dark mode',
() {
_expectLightMode(buildEmailHtml('<p>Hello</p>'));
});
test('includes email body content', () {
final html = buildEmailHtml('<p>Test body</p>');
expect(html, contains('<p>Test body</p>'));
});
test('blocks remote images by default', () {
final html = buildEmailHtml('<p>x</p>');
expect(html, contains('img-src data: blob:'));
expect(html, isNot(contains('img-src https:')));
});
test('allows remote images when loadRemoteImages is true', () {
final html = buildEmailHtml('<p>x</p>', loadRemoteImages: true);
expect(html, contains('https: http: data: blob:'));
_expectLightMode(html);
});
});
// On Linux (the test host) the widget falls back to plain text extracted via
// htmlToPlain(). These tests exercise that path.
group('SecureEmailWebView (Linux plain-text fallback)', () {
testWidgets('renders extracted text from HTML', (tester) async {
await tester.pumpWidget(
_wrap(
const SecureEmailWebView(
htmlBody: '<p>Hello <b>world</b></p>',
),
),
);
expect(find.textContaining('Hello'), findsOneWidget);
expect(find.textContaining('world'), findsOneWidget);
});
testWidgets('strips HTML tags from body', (tester) async {
await tester.pumpWidget(
_wrap(
const SecureEmailWebView(
htmlBody:
'<p>Clean text</p><br/><span style="color:red">More</span>',
),
),
);
expect(find.textContaining('<'), findsNothing);
expect(find.textContaining('Clean text'), findsOneWidget);
});
testWidgets('shows SelectableText widget', (tester) async {
await tester.pumpWidget(
_wrap(const SecureEmailWebView(htmlBody: '<p>Test</p>')),
);
expect(find.byType(SelectableText), findsOneWidget);
});
testWidgets('toggling loadRemoteImages rebuilds without error',
(tester) async {
await tester.pumpWidget(
_wrap(
const SecureEmailWebView(htmlBody: '<p>Body</p>'),
),
);
await tester.pumpWidget(
_wrap(
const SecureEmailWebView(
htmlBody: '<p>Body</p>',
loadRemoteImages: true,
),
),
);
expect(find.byType(SelectableText), findsOneWidget);
});
testWidgets('handles empty HTML body', (tester) async {
await tester.pumpWidget(
_wrap(const SecureEmailWebView(htmlBody: '')),
);
expect(find.byType(SelectableText), findsOneWidget);
});
});
}