cometchat-flutter-v6-testing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cometchat-flutter-v6-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 v6 (stable, Bloc-based). Most of the v5 patterns carry over; the deltas are around state-management primitives (Bloc, not GetX) and the unified cometchat_chat_uikit package (calls bundled — see cometchat-flutter-v6-calls).
Read these other skills first:
cometchat-flutter-v6-core — UIKitSettings, init/login order, hard rulescometchat-flutter-v6-events — Bloc-based event streamscometchat-flutter-v5-testing — patterns that aren't v6-specific (CI config, golden tests, mocktail intro) — read first if you haven'tGround truth: Official docs: https://www.cometchat.com/docs/ui-kit/flutter/overview · Docs MCP: claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp (or fetch the URL directly without MCP).
| Concern | v5 | v6 |
|---|---|---|
| State management | GetX | Bloc |
| DI in tests | Get.reset() between tests | Provide via MultiBlocProvider per test, or use BlocProvider.value with a mock |
| Calls package | cometchat_calls_uikit (separate) | bundled into cometchat_chat_uikit |
| Init order | ..callingExtension = CometChatCallingExtension() on UIKitSettingsBuilder | CometChatUIKitCalls.init inside CometChatUIKit.init onSuccess |
| Listener IDs | Stable string for addCallListener | Bloc subscription, automatic cleanup |
| State persistence between tests | Get singletons leak — must reset | Bloc state is per-instance — no global reset, but providers must be re-created per test |
Most assertions stay the same; the wiring around them changes.
# pubspec.yaml
dev_dependencies:
flutter_test:
sdk: flutter
bloc_test: ^9.0.0
mocktail: ^1.0.0
integration_test:
sdk: flutterSame shape as v5 (see cometchat-flutter-v5-testing/SKILL.md Section 2):
// lib/services/cometchat_service.dart
abstract class CometChatService {
Future<void> init();
Future<User> login(String uid);
Future<void> logout();
User? getLoggedInUser();
Stream<TextMessage> messageStream();
}
class CometChatServiceImpl implements CometChatService {
@override
Future<void> init() async {
// Class is UIKitSettingsBuilder (constructor), NOT UIKitSettings.builder() (verified shared_uikit/lib/src/cometchat_ui_kit/ui_kit_settings.dart).
final settings = (UIKitSettingsBuilder()
..appId = CometChatConfig.appId
..region = CometChatConfig.region
..authKey = CometChatConfig.authKey
..subscriptionType = CometChatSubscriptionType.allUsers)
.build();
await Future<void>.value(); // Real impl: completer-wrap CometChatUIKit.init
// Then chain calls init in onSuccess (rule 1.1 from cometchat-flutter-v6-calls)
}
// ... rest
}// test/blocs/auth_bloc_test.dart
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:your_app/blocs/auth_bloc.dart';
import 'package:your_app/services/cometchat_service.dart';
class MockCometChatService extends Mock implements CometChatService {}
class FakeAuthEvent extends Fake implements AuthEvent {}
void main() {
late MockCometChatService mockService;
setUpAll(() {
registerFallbackValue(FakeAuthEvent());
});
setUp(() {
mockService = MockCometChatService();
});
blocTest<AuthBloc, AuthState>(
'emits Authenticated when login succeeds',
setUp: () {
when(() => mockService.init()).thenAnswer((_) async {});
when(() => mockService.login(any())).thenAnswer(
(_) async => User(uid: 'cometchat-uid-1', name: 'Alice'),
);
},
build: () => AuthBloc(service: mockService),
act: (bloc) => bloc.add(LoginRequested(uid: 'cometchat-uid-1')),
expect: () => [
isA<AuthLoading>(),
isA<Authenticated>(),
],
verify: (_) {
verify(() => mockService.init()).called(1);
verify(() => mockService.login('cometchat-uid-1')).called(1);
},
);
blocTest<AuthBloc, AuthState>(
'emits AuthError when login fails',
setUp: () {
when(() => mockService.init()).thenAnswer((_) async {});
when(() => mockService.login(any())).thenThrow(Exception('401 Unauthorized'));
},
build: () => AuthBloc(service: mockService),
act: (bloc) => bloc.add(LoginRequested(uid: 'cometchat-uid-1')),
expect: () => [
isA<AuthLoading>(),
predicate<AuthState>((s) => s is AuthError && s.message.contains('Unauthorized')),
],
);
}bloc_test handles the boilerplate of subscribing to the bloc, dispatching events, and asserting state sequence.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mocktail/mocktail.dart';
import 'package:your_app/screens/chat_screen.dart';
import 'package:your_app/blocs/auth_bloc.dart';
class MockAuthBloc extends MockBloc<AuthEvent, AuthState> implements AuthBloc {}
class FakeAuthState extends Fake implements AuthState {}
class FakeAuthEvent extends Fake implements AuthEvent {}
void main() {
setUpAll(() {
registerFallbackValue(FakeAuthState());
registerFallbackValue(FakeAuthEvent());
});
testWidgets('shows loading on AuthLoading state', (tester) async {
final mockBloc = MockAuthBloc();
when(() => mockBloc.state).thenReturn(AuthLoading());
await tester.pumpWidget(
MaterialApp(
home: BlocProvider<AuthBloc>.value(
value: mockBloc,
child: ChatScreen(),
),
),
);
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
testWidgets('shows error on AuthError state', (tester) async {
final mockBloc = MockAuthBloc();
when(() => mockBloc.state).thenReturn(AuthError(message: '401 Unauthorized'));
await tester.pumpWidget(
MaterialApp(
home: BlocProvider<AuthBloc>.value(value: mockBloc, child: ChatScreen()),
),
);
expect(find.textContaining('Unauthorized'), findsOneWidget);
});
}BlocProvider.value is for tests; BlocProvider(create: ...) is for production.
V6 calls widgets fire BLoC events internally. Mocking is the same pattern — wrap your custom call surfaces in service abstractions, mock at that layer.
For widgets like <CometChatOngoingCall> that you don't control, the strategy is the same as v5: replace at composition boundary or skip widget tests for them and rely on integration tests.
// 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));
expect(find.text('Welcome'), findsOneWidget);
await tester.tap(find.text('Messages'));
await tester.pumpAndSettle();
expect(find.byType(ListTile), findsAtLeastNWidgets(1));
});
}Same shape as v5; the underlying SDK is different but the integration test contract is the same.
See cometchat-flutter-v5-testing/SKILL.md Section 6 — the patterns are identical. The kit's V6 themes use Material 3 by default; pin Flutter version to ensure golden stability.
V6 bundles calls into cometchat_chat_uikit. Tests that touch calls:
blocTest<CallBloc, CallState>(
'emits CallActive when initiateCall succeeds',
setUp: () {
when(() => mockService.initiateCall(any())).thenAnswer(
(_) async => Call(sessionId: 'session-123'),
);
},
build: () => CallBloc(service: mockService),
act: (bloc) => bloc.add(InitiateCall(receiverUid: 'cometchat-uid-2')),
expect: () => [isA<CallInitiating>(), isA<CallActive>()],
);The init order rule applies in tests too: mock init to resolve before any initiateCall-related test runs. The simplest way is to wire init in your test's setUpAll:
setUpAll(() async {
registerFallbackValue(FakeCallEvent());
// If your AuthBloc init is shared, run it once here:
// await mockAuthBloc.add(AppStarted());
});For widget tests of call screens, see cometchat-flutter-v6-calls Section 7's verification checklist — the same checks belong in the test file:
endSession AND Navigator.pop?tearDown(() => mockBloc.close()).Equatable mixed in; if not, expect: () => [SomeState()] fails because two SomeState() instances aren't equal. Use predicate<T>(...) or verify via isA<SomeState>() + later assertions.BlocProvider.value(value: mockBloc).bloc_test handles state assertions, but widget tests need explicit await tester.pump() after the bloc emits or the rebuild won't happen.CometChatService abstraction wrapping the SDKMockCometChatService and MockAuthBloc (MockBloc<E, S>) in test filesregisterFallbackValue calls in setUpAll for events + states--dart-definecometchat-flutter-v6-core — init/login order, hard rulescometchat-flutter-v6-events — Bloc event streamscometchat-flutter-v6-calls — calls integration; hard rules to assert in testscometchat-flutter-v6-troubleshooting — when tests pass but production breakscometchat-flutter-v5-testing — for shared patterns (CI, goldens, mocktail intro)cometchat-flutter-v6-migration — v5 → v6 migration recipes (test rewrites)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.