Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .cursorindexingignore

This file was deleted.

74 changes: 74 additions & 0 deletions .github/cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# git-cliff configuration file for flutter_hooks_test
# https://git-cliff.org/docs/configuration

[changelog]
# changelog header
header = """
# Changelog

All notable changes to this project will be documented in this file.

"""
# template for the changelog body
# https://keats.github.io/tera/docs/
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/wasabeef/flutter_hooks_test/commit/{{ commit.id }}))
{%- endfor %}
{% endfor %}\n
"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
<!-- generated by git-cliff -->
"""

[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/wasabeef/flutter_hooks_test/issues/${2}))"},
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "Features"},
{ message = "^fix", group = "Bug Fixes"},
{ message = "^docs", group = "Documentation"},
{ message = "^perf", group = "Performance"},
{ message = "^refactor", group = "Refactor"},
{ message = "^style", group = "Styling"},
{ message = "^test", group = "Testing"},
{ message = "^chore\\(release\\): prepare for", skip = true},
{ message = "^chore", group = "Miscellaneous Tasks"},
{ body = ".*security", group = "Security"},
{ message = "^upgrade", group = "Dependencies"},
{ message = "^add", group = "Features"},
{ message = "^update", group = "Improvements"},
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# filter out the commits that are not matched by commit parsers
filter_commits = false
# glob pattern for matching git tags
tag_pattern = "v[0-9]*"
# regex for skipping tags
skip_tags = ""
# regex for ignoring tags
ignore_tags = ""
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
16 changes: 13 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v4

Expand All @@ -26,15 +26,25 @@ jobs:
flutter-version: ${{ steps.asdf.outputs.flutter }}
cache: true

- uses: dart-lang/setup-dart@v1
with:
sdk: ${{ steps.asdf.outputs.dart }}

- name: Set environment
run: echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
run: echo "$HOME/.pub-cache/bin" >> "$GITHUB_PATH"

- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ steps.asdf.outputs.bun }}

- name: Get dependencies
run: |
dart pub global activate melos
melos get
bun install

- name: Run tests for our dart project.
- name: Run tests with coverage
run: |
melos test

Expand Down
65 changes: 50 additions & 15 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
name: Publish to pub.dev
name: Release

on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+' # Tag pattern to match for publishing
- 'v[0-9]+.[0-9]+.[0-9]+*'

permissions:
contents: write
id-token: write # Required for OIDC authentication

jobs:
publish:
release:
name: Release and Publish
runs-on: ubuntu-latest
permissions:
id-token: write # Required for authentication using OIDC
contents: write
steps:
- name: Checkout repository
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Import .tool-versions
uses: wasabeef/import-asdf-tool-versions-action@v1.1.0
Expand All @@ -25,22 +29,53 @@ jobs:
flutter-version: ${{ steps.asdf.outputs.flutter }}
cache: true

- name: Setup Dart for publishing
- name: Setup Dart
uses: dart-lang/setup-dart@v1
with:
sdk: ${{ steps.asdf.outputs.dart }}

- name: Setup Melos
- name: Set environment
run: echo "$HOME/.pub-cache/bin" >> "$GITHUB_PATH"

- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ steps.asdf.outputs.bun }}

- name: Install Melos
run: dart pub global activate melos

- name: Get Melos packages
run: melos bootstrap
- name: Bootstrap packages
run: |
melos bootstrap
bun install

- name: Publish package
run: dart pub publish --force
- name: Verify all tests pass
run: melos test

- name: Verify code formatting
run: melos format && melos analyze

- name: Check package can be published (dry-run)
run: dart pub publish --dry-run

- name: Generate release notes
id: release_notes
uses: orhun/git-cliff-action@v3
with:
config: .github/cliff.toml
args: --latest --strip header

- name: Create GitHub Release
uses: softprops/action-gh-release@v2 # Consider using a more recent version
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
body: ${{ steps.release_notes.outputs.content }}
draft: false
prerelease: false

- name: Publish to pub.dev
run: dart pub publish --force
5 changes: 0 additions & 5 deletions .husky/pre-commit

This file was deleted.

151 changes: 151 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Flutter Hooks Test is a testing utility library for Flutter hooks, inspired by React's `react-hooks-testing-library`. It provides a simple API to test custom hooks in isolation.

## Development Commands

### Essential Commands

```bash
# Install dependencies
melos get
bun install

# Run tests
melos test

# Run code analysis
melos analyze

# Format code (Dart + Prettier)
melos format

# Run all checks (analyze + format + test)
melos analyze && melos format && melos test

# Run a single test file
flutter test test/flutter_hooks_test_test.dart

# Run tests with coverage
flutter test --coverage
```

### Additional Commands

```bash
# Upgrade dependencies
melos upgrade

# Clean build artifacts
melos clean

# Format with Prettier only
bun run format

# Setup git hooks
bun run prepare
```

## Architecture and Code Structure

### Core API

The library exports a single file `lib/flutter_hooks_test.dart` containing:

1. **`buildHook<T, P>`** - Main function to test hooks
- Generic `T`: Return type of the hook
- Generic `P`: Props type for parameterized hooks
- Returns `_HookTestingAction<T>` with methods:
- `current`: Access current hook value
- `rebuild([props])`: Trigger rebuild with optional new props
- `unmount()`: Unmount the hook

2. **`act`** - Wraps state changes to ensure proper Flutter test lifecycle
- Similar to React's `act` function
- Required when changing hook state

### Testing Pattern

```dart
// Basic hook test structure
final result = await buildHook((_) => useMyHook());
await act(() => result.current.doSomething());
expect(result.current.value, expectedValue);

// With wrapper widget
final result = await buildHook(
(_) => useMyHook(),
wrapper: (child) => Provider(child: child),
);
```

### Internal Implementation

- Uses `TestWidgetsFlutterBinding` for test environment
- Creates a minimal widget tree with `HookBuilder`
- Manages completer-based async operations for mount/unmount
- Preserves hook state across rebuilds using keys

## Testing Approach

- All tests go in `test/` directory
- Example hooks in `test/hooks/` demonstrate testable patterns
- Use `testWidgets` for widget-based tests
- Use Mockito for mocking dependencies

## Code Quality

- Flutter lints are enforced via `analysis_options.yaml`
- Example directory is excluded from analysis
- Pre-commit hooks format code automatically
- CI runs on Ubuntu with asdf version management

## Important Conventions

1. **Type Safety**: Always specify generic types when using `buildHook`
2. **Act Wrapper**: Always wrap state changes in `act()`
3. **Async Handling**: Most operations return Futures - use `await`
4. **Testing**: Test both happy paths and edge cases (mount/unmount/rebuild)

## Version Requirements

- Dart SDK: `>=2.17.0 <4.0.0`
- Flutter: `>=3.20.0`
- Uses Flutter hooks `^0.21.2`

## Release Process

Releases are fully automated via GitHub Actions:

### Creating a Release

1. **Update version**: Update version in `pubspec.yaml`
2. **Update changelog**: Run `git cliff --unreleased --tag v1.0.1 --output CHANGELOG.md`
3. **Commit changes**: `git commit -am "chore(release): prepare for v1.0.1"`
4. **Create tag**: `git tag v1.0.1`
5. **Push**: `git push origin main --tags`

### Automated Release Steps

When a tag matching `v[0-9]+.[0-9]+.[0-9]+*` is pushed:

1. **CI Validation**: All tests, formatting, and analysis must pass
2. **Dry Run**: Package publication is tested
3. **Release Notes**: Auto-generated using git-cliff from conventional commits
4. **GitHub Release**: Created with generated release notes
5. **pub.dev Publication**: Package is published automatically

### Commit Convention

Use [Conventional Commits](https://www.conventionalcommits.org/) for automatic release note generation:

- `feat:` - New features
- `fix:` - Bug fixes
- `docs:` - Documentation changes
- `test:` - Test improvements
- `refactor:` - Code refactoring
- `perf:` - Performance improvements
Loading
Loading