cometchat-flutter-v5-testing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cometchat-flutter-v5-testing (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Test recipes for Flutter UIKit v5. Covers the GetX-flavored patterns; v6 (Bloc) has its own skill (cometchat-flutter-v6-testing).
Read these other skills first:
cometchat-flutter-v5-core — UIKitSettingsBuilder, init/login order, GetX scope rulescometchat-flutter-v5-events — event subscription patterns the tests assert againstGround truth: Official docs: https://www.cometchat.com/docs/ui-kit/flutter/v5/overview · Docs MCP: claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp (or fetch the URL directly without MCP).
| Layer | Test runner | Speed | What it covers |
|---|---|---|---|
| Unit | flutter test (Dart VM) | Fastest | Pure Dart logic — services, models |
| Widget | flutter test (test environment) | Fast | Single widget, mocked dependencies |
| Integration | flutter test integration_test/ (real device or simulator) | Slow | Full app flow, real SDK or mocked |
| Golden | flutter test --update-goldens then assert | Fast | Visual regression |
The skill writes all four; CI runs unit + widget + golden by default; integration runs on demand.
# pubspec.yaml — dev dependencies
dev_dependencies:
flutter_test:
sdk: flutter
mocktail: ^1.0.0
integration_test:
sdk: flutter// lib/services/cometchat_service.dart
import 'package:cometchat_calls_uikit/cometchat_calls_uikit.dart';
abstract class CometChatService {
Future<void> init();
Future<User> login(String uid);
Future<void> logout();
User? getLoggedInUser();
Future<TextMessage> sendMessage(TextMessage message);
}
class CometChatServiceImpl implements CometChatService {
@override
Future<void> init() async {
final settings = (UIKitSettingsBuilder()
..appId = CometChatConfig.appId
..region = CometChatConfig.region
..authKey = CometChatConfig.authKey
..subscriptionType = CometChatSubscriptionType.allUsers
..callingExtension = CometChatCallingExtension())
.build();
await CometChatUIKit.init(uiKitSettings: settings);
}
@override
Future<User> login(String uid) async {
final completer = Completer<User>();
CometChatUIKit.login(uid, onSuccess: completer.complete, onError: completer.completeError);
return completer.future;
}
@override
Future<void> logout() async {
final completer = Completer<void>();
CometChatUIKit.logout(onSuccess: () => completer.complete(), onError: completer.completeError);
return completer.future;
}
@override
// Sync accessor → the static field. CometChatUIKit.getLoggedInUser() is async
// (Future<User?>) and would not satisfy this `User?` signature.
User? getLoggedInUser() => CometChatUIKit.loggedInUser;
@override
Future<TextMessage> sendMessage(TextMessage message) async {
final completer = Completer<TextMessage>();
// sendTextMessage takes message as positional, not named (verified cometchat_ui_kit.dart:357).
CometChatUIKit.sendTextMessage(message, onSuccess: completer.complete, onError: completer.completeError);
return completer.future;
}
}Inject via your DI / GetX scope:
final cometchatService = Get.put<CometChatService>(CometChatServiceImpl());In tests, swap with a mock:
class MockCometChatService extends Mock implements CometChatService {}
setUp(() {
Get.reset();
final mock = MockCometChatService();
when(() => mock.init()).thenAnswer((_) async {});
when(() => mock.login(any())).thenAnswer((_) async => testUser);
Get.put<CometChatService>(mock);
});
tearDown(() {
Get.reset();
});`Get.reset()` between tests is critical — GetX's singleton container persists across tests otherwise.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:get/get.dart';
import 'package:your_app/screens/chat_screen.dart';
import 'package:your_app/services/cometchat_service.dart';
class MockCometChatService extends Mock implements CometChatService {}
void main() {
late MockCometChatService mock;
setUp(() {
Get.reset();
mock = MockCometChatService();
when(() => mock.init()).thenAnswer((_) async {});
when(() => mock.login(any())).thenAnswer((_) async => User(uid: 'cometchat-uid-1', name: 'Alice'));
Get.put<CometChatService>(mock);
});
tearDown(() => Get.reset());
testWidgets('shows loading until login resolves', (tester) async {
final loginCompleter = Completer<User>();
when(() => mock.login(any())).thenAnswer((_) => loginCompleter.future);
await tester.pumpWidget(MaterialApp(home: ChatScreen()));
await tester.pump(); // start the build
expect(find.byType(CircularProgressIndicator), findsOneWidget);
// User constructor requires both uid AND name (verified User constructor in chat-sdk-flutter).
loginCompleter.complete(User(uid: 'cometchat-uid-1', name: 'Alice'));
await tester.pumpAndSettle();
expect(find.byType(CircularProgressIndicator), findsNothing);
expect(find.text('Conversations'), findsOneWidget);
});
testWidgets('shows error when login fails', (tester) async {
when(() => mock.login(any())).thenThrow(Exception('401 Unauthorized'));
await tester.pumpWidget(MaterialApp(home: ChatScreen()));
await tester.pumpAndSettle();
expect(find.textContaining('Unauthorized'), findsOneWidget);
});
}pumpAndSettle() waits for animations + Futures to complete.
CometChatConversations, CometChatMessageList, etc. are real widgets that try to render against a real SDK during tests. Two strategies:
If your widget composition is small (3-5 CometChat widgets), make them swappable:
// chat_screen.dart
class ChatScreen extends StatelessWidget {
final WidgetBuilder conversationsBuilder;
const ChatScreen({this.conversationsBuilder = _defaultConversations});
static Widget _defaultConversations(BuildContext context) =>
const CometChatConversations();
@override
Widget build(BuildContext context) => Scaffold(body: conversationsBuilder(context));
}
// In tests:
testWidgets('chat screen renders', (tester) async {
await tester.pumpWidget(MaterialApp(
home: ChatScreen(conversationsBuilder: (_) => const Text('mock convo list')),
));
expect(find.text('mock convo list'), findsOneWidget);
});For larger compositions, test the service layer (which is fully mockable) and rely on integration tests for widget assertions. Pragmatic for v5 because the kit's widgets aren't designed for unit testing.
// integration_test/chat_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:your_app/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('login and see conversations', (tester) async {
app.main();
await tester.pumpAndSettle(Duration(seconds: 10)); // generous for real SDK init
expect(find.text('Welcome'), findsOneWidget);
await tester.tap(find.text('Messages'));
await tester.pumpAndSettle();
// Real SDK + real test app: assert that at least one conversation exists
// (cometchat-uid-1 has pre-seeded conversations with uid-2..5)
expect(find.byType(ListTile), findsAtLeastNWidgets(1));
});
}Run on a real device or simulator:
flutter test integration_test/chat_test.dartFor CI:
flutter test integration_test/chat_test.dart --device-id=emulator-5554testWidgets('chat bubble renders correctly in light theme', (tester) async {
await tester.pumpWidget(MaterialApp(
theme: ThemeData.light(),
home: Scaffold(
body: ChatBubble(
// TextMessage requires: text, receiverUid, type, receiverType + sender (User object).
// senderUid is NOT a TextMessage constructor param — set via sender (User).
message: TextMessage(
text: 'Hello',
receiverUid: 'bob',
type: 'text',
receiverType: 'user',
sender: User(uid: 'alice', name: 'Alice'),
),
),
),
));
await expectLater(
find.byType(ChatBubble),
matchesGoldenFile('goldens/chat_bubble_light.png'),
);
});First run:
flutter test --update-goldensCommit the goldens/ folder. Subsequent runs assert against it.
Gotcha: golden tests are pixel-perfect; small rendering differences between Flutter versions / OS versions cause failures. Pin Flutter SDK version in CI.
name: tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with: { flutter-version: 3.16.0, channel: stable }
- run: flutter pub get
- run: flutter test
env:
COMETCHAT_TEST_APP_ID: ${{ secrets.TEST_COMETCHAT_APP_ID }}
COMETCHAT_TEST_REGION: ${{ secrets.TEST_COMETCHAT_REGION }}
COMETCHAT_TEST_AUTH_KEY: ${{ secrets.TEST_COMETCHAT_AUTH_KEY }}
integration:
runs-on: macos-13
needs: test
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with: { flutter-version: 3.16.0, channel: stable }
- uses: futureware-tech/simulator-action@v3
with: { model: "iPhone 15", os: iOS, os_version: "17.0" }
- run: flutter pub get
- run: |
flutter test integration_test/chat_test.dart \
--dart-define=COMETCHAT_APP_ID=${{ secrets.TEST_COMETCHAT_APP_ID }} \
--dart-define=COMETCHAT_REGION=${{ secrets.TEST_COMETCHAT_REGION }} \
--dart-define=COMETCHAT_AUTH_KEY=${{ secrets.TEST_COMETCHAT_AUTH_KEY }}Codemagic is Flutter-native. Add a workflow:
workflows:
test:
name: Flutter tests
instance_type: mac_mini_m1
scripts:
- name: Get dependencies
script: flutter pub get
- name: Run tests
script: flutter test
- name: Run integration tests
script: |
flutter test integration_test/chat_test.dart \
--dart-define=COMETCHAT_APP_ID=$COMETCHAT_APP_ID \
...Codemagic's env vars come from the project settings UI.
Duration(seconds: 10) explicitly.Get.put requires every injected service; partial mocks crash with "not registered."--dart-define flags. Same rule as production.Roboto (Material default) and pin Flutter SDK version.init in a unit test, the test slows to seconds and may flake. Mock the service.CometChatService abstraction (or similar) wrapping the SDKMockCometChatService in test setup; Get.put<CometChatService>(mock) per testGet.reset() in tearDownintegration_test/ for the login + see conversations flow--dart-definecometchat-flutter-v5-core — UIKitSettingsBuilder, init/login ordercometchat-flutter-v5-events — listener subscription patternscometchat-flutter-v5-troubleshooting — when tests pass but production breakscometchat-flutter-v6-testing — V6 patterns (Bloc-based; different)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.