smithery/marcglasberg

setup-test

Set up proper test configuration for Cubits using bloc_superpowers with Superpowers.clear() and Completers

Installation

$ npx skills add smithery/marcglasberg --skill setup-test

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/marcglasberg · top by installs.

npx skills add smithery/marcglasberg

Browse all from smithery/marcglasberg

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,646 B
  • docs SUMMARY.md 124 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Set Up Tests for bloc_superpowers

This skill sets up proper test configuration for Cubits using bloc_superpowers.

What This Skill Does

Configures tests to:

  • Reset Superpowers state between tests
  • Properly test loading and error states
  • Use Completers for async test control

Instructions

Step 1: Add setUp with Superpowers.clear()

Always call Superpowers.clear() in setUp to reset state between tests:

import 'package:bloc_superpowers/bloc_superpowers.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  setUp(() {
    Superpowers.clear();  // IMPORTANT: Reset state between tests
  });

  // ... tests
}

Step 2: Test Structure

import 'package:bloc_superpowers/bloc_superpowers.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

class MockApi extends Mock implements Api {}

void main() {
  late UserCubit cubit;
  late MockApi mockApi;

  setUp(() {
    Superpowers.clear();  // Reset Superpowers state
    mockApi = MockApi();
    cubit = UserCubit(api: mockApi);
  });

  tearDown(() {
    cubit.close();
  });

  group('UserCubit', () {
    test('initial state is correct', () {
      expect(cubit.state, const UserState());
    });

    // ... more tests
  });
}

Step 3: Test with Completers for Async Control

Use Completer to control when async operations complete:

test('loadUser sets loading state while fetching', () async {
  final completer = Completer<User>();

  // Mock returns a future that we control
  when(() => mockApi.getUser()).thenAnswer((_) => completer.future);

  // Start the operation
  cubit.loadUser();

  // Wait for next event loop
  await Future.delayed(Duration.zero);

  // Check loading state
  expect(Superpowers.isWaiting(UserCubit), isTrue);

  // Complete the operation
  completer.complete(User(name: 'John'));

  // Wait for completion
  await Future.delayed(Duration.zero);

  // Check final state
  expect(Superpowers.isWaiting(UserCubit), isFalse);
  expect(cubit.state.user?.name, 'John');
});

Testing Loading State

Using Static Method

test('isWaiting is true during load', () async {
  final completer = Completer<User>();
  when(() => mockApi.getUser()).thenAnswer((_) => completer.future);

  cubit.loadUser();
  await Future.delayed(Duration.zero);

  // Use static method
  expect(Superpowers.isWaiting(UserCubit), isTrue);

  completer.complete(User(name: 'John'));
  await Future.delayed(Duration.zero);

  expect(Superpowers.isWaiting(UserCubit), isFalse);
});

With Composite Keys

test('per-item loading state', () async {
  final completer = Completer<void>();
  when(() => mockApi.deleteItem('123')).thenAnswer((_) => completer.future);

  cubit.deleteItem('123');
  await Future.delayed(Duration.zero);

  // Check specific item key
  expect(Superpowers.isWaiting((DeleteItem, '123')), isTrue);
  expect(Superpowers.isWaiting((DeleteItem, '456')), isFalse);

  completer.complete();
  await Future.delayed(Duration.zero);

  expect(Superpowers.isWaiting((DeleteItem, '123')), isFalse);
});

Testing Error State

test('isFailed is true after error', () async {
  when(() => mockApi.getUser()).thenThrow(Exception('Network error'));

  cubit.loadUser();
  await Future.delayed(Duration.zero);

  expect(Superpowers.isFailed(UserCubit), isTrue);
  expect(Superpowers.getException(UserCubit), isA<UserException>());
});

test('error clears on retry', () async {
  // First call fails
  when(() => mockApi.getUser()).thenThrow(Exception('Network error'));
  cubit.loadUser();
  await Future.delayed(Duration.zero);
  expect(Superpowers.isFailed(UserCubit), isTrue);

  // Second call succeeds
  when(() => mockApi.getUser()).thenAnswer((_) async => User(name: 'John'));
  cubit.loadUser();
  await Future.delayed(Duration.zero);

  expect(Superpowers.isFailed(UserCubit), isFalse);
  expect(cubit.state.user?.name, 'John');
});

Testing with bloc_test

blocTest<UserCubit, UserState>(
  'emits user when loadUser succeeds',
  setUp: () {
    Superpowers.clear();  // Reset in setUp
    when(() => mockApi.getUser()).thenAnswer(
      (_) async => User(name: 'John'),
    );
  },
  build: () => UserCubit(api: mockApi),
  act: (cubit) => cubit.loadUser(),
  expect: () => [
    UserState(user: User(name: 'John')),
  ],
);

Testing Effects

test('effect is emitted on success', () async {
  when(() => mockApi.saveUser(any())).thenAnswer((_) async {});

  cubit.saveUser(User(name: 'John'));
  await Future.delayed(Duration.zero);

  // Check effect was emitted
  expect(cubit.state.successMessageEffect.isNotSpent, isTrue);

  // Consume the effect
  final message = cubit.state.successMessageEffect.consume();
  expect(message, 'User saved!');

  // Effect is now spent
  expect(cubit.state.successMessageEffect.isSpent, isTrue);
});

Complete Test Example

import 'package:bloc_superpowers/bloc_superpowers.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

class MockApi extends Mock implements Api {}

void main() {
  late ProductCubit cubit;
  late MockApi mockApi;

  setUp(() {
    Superpowers.clear();
    mockApi = MockApi();
    cubit = ProductCubit(api: mockApi);
  });

  tearDown(() {
    cubit.close();
  });

  group('loadProducts', () {
    test('sets loading state while fetching', () async {
      final completer = Completer<List<Product>>();
      when(() => mockApi.getProducts()).thenAnswer((_) => completer.future);

      cubit.loadProducts();
      await Future.delayed(Duration.zero);

      expect(Superpowers.isWaiting(ProductCubit), isTrue);

      completer.complete([Product(id: '1', name: 'Widget')]);
      await Future.delayed(Duration.zero);

      expect(Superpowers.isWaiting(ProductCubit), isFalse);
      expect(cubit.state.products.length, 1);
    });

    test('sets error state on failure', () async {
      when(() => mockApi.getProducts()).thenThrow(Exception('Error'));

      cubit.loadProducts();
      await Future.delayed(Duration.zero);

      expect(Superpowers.isFailed(ProductCubit), isTrue);
    });
  });

  group('deleteProduct', () {
    test('tracks loading per product', () async {
      final completer = Completer<void>();
      when(() => mockApi.deleteProduct('1')).thenAnswer((_) => completer.future);

      cubit.deleteProduct('1');
      await Future.delayed(Duration.zero);

      expect(Superpowers.isWaiting((DeleteProduct, '1')), isTrue);
      expect(Superpowers.isWaiting((DeleteProduct, '2')), isFalse);

      completer.complete();
      await Future.delayed(Duration.zero);

      expect(Superpowers.isWaiting((DeleteProduct, '1')), isFalse);
    });
  });
}

Key Points

  1. Always call Superpowers.clear() in setUp - Prevents state leaking between tests
  2. Use Completer for async control - Allows testing intermediate states
  3. Use Future.delayed(Duration.zero) - Allows async operations to process
  4. Test both isWaiting and isFailed - Cover loading and error states
  5. Test with composite keys - For per-item operations

User Preferences

Ask the user:

  1. What Cubit is being tested?
  2. What operations need testing? (load, save, delete)
  3. Need to test loading states? (use Completer pattern)
  4. Need to test error states? (mock throws)