Skip to content

Commit 2b64440

Browse files
authored
Merge pull request #50 from wasabeef/refactor-code-quality-improvements
2 parents 9ba2c58 + af0900b commit 2b64440

File tree

17 files changed

+698
-303
lines changed

17 files changed

+698
-303
lines changed

.cursorindexingignore

Lines changed: 0 additions & 3 deletions
This file was deleted.

.github/cliff.toml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# git-cliff configuration file for flutter_hooks_test
2+
# https://git-cliff.org/docs/configuration
3+
4+
[changelog]
5+
# changelog header
6+
header = """
7+
# Changelog
8+
9+
All notable changes to this project will be documented in this file.
10+
11+
"""
12+
# template for the changelog body
13+
# https://keats.github.io/tera/docs/
14+
body = """
15+
{% if version %}\
16+
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
17+
{% else %}\
18+
## [unreleased]
19+
{% endif %}\
20+
{% for group, commits in commits | group_by(attribute="group") %}
21+
### {{ group | upper_first }}
22+
{% for commit in commits %}
23+
- {% 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 }}))
24+
{%- endfor %}
25+
{% endfor %}\n
26+
"""
27+
# remove the leading and trailing whitespace from the template
28+
trim = true
29+
# changelog footer
30+
footer = """
31+
<!-- generated by git-cliff -->
32+
"""
33+
34+
[git]
35+
# parse the commits based on https://www.conventionalcommits.org
36+
conventional_commits = true
37+
# filter out the commits that are not conventional
38+
filter_unconventional = true
39+
# process each line of a commit as an individual commit
40+
split_commits = false
41+
# regex for preprocessing the commit messages
42+
commit_preprocessors = [
43+
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/wasabeef/flutter_hooks_test/issues/${2}))"},
44+
]
45+
# regex for parsing and grouping commits
46+
commit_parsers = [
47+
{ message = "^feat", group = "Features"},
48+
{ message = "^fix", group = "Bug Fixes"},
49+
{ message = "^docs", group = "Documentation"},
50+
{ message = "^perf", group = "Performance"},
51+
{ message = "^refactor", group = "Refactor"},
52+
{ message = "^style", group = "Styling"},
53+
{ message = "^test", group = "Testing"},
54+
{ message = "^chore\\(release\\): prepare for", skip = true},
55+
{ message = "^chore", group = "Miscellaneous Tasks"},
56+
{ body = ".*security", group = "Security"},
57+
{ message = "^upgrade", group = "Dependencies"},
58+
{ message = "^add", group = "Features"},
59+
{ message = "^update", group = "Improvements"},
60+
]
61+
# protect breaking changes from being skipped due to matching a skipping commit_parser
62+
protect_breaking_commits = false
63+
# filter out the commits that are not matched by commit parsers
64+
filter_commits = false
65+
# glob pattern for matching git tags
66+
tag_pattern = "v[0-9]*"
67+
# regex for skipping tags
68+
skip_tags = ""
69+
# regex for ignoring tags
70+
ignore_tags = ""
71+
# sort the tags topologically
72+
topo_order = false
73+
# sort the commits inside sections by oldest/newest order
74+
sort_commits = "oldest"

.github/workflows/ci.yaml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ${{ matrix.os }}
1313
strategy:
1414
matrix:
15-
os: [ubuntu-latest]
15+
os: [ubuntu-latest, macos-latest]
1616
steps:
1717
- uses: actions/checkout@v4
1818

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

29+
- uses: dart-lang/setup-dart@v1
30+
with:
31+
sdk: ${{ steps.asdf.outputs.dart }}
32+
2933
- name: Set environment
30-
run: echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
34+
run: echo "$HOME/.pub-cache/bin" >> "$GITHUB_PATH"
35+
36+
- name: Setup Bun
37+
uses: oven-sh/setup-bun@v1
38+
with:
39+
bun-version: ${{ steps.asdf.outputs.bun }}
3140

3241
- name: Get dependencies
3342
run: |
3443
dart pub global activate melos
3544
melos get
45+
bun install
3646
37-
- name: Run tests for our dart project.
47+
- name: Run tests with coverage
3848
run: |
3949
melos test
4050

.github/workflows/release.yaml

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
name: Publish to pub.dev
1+
name: Release
22

33
on:
44
push:
55
tags:
6-
- 'v[0-9]+.[0-9]+.[0-9]+' # Tag pattern to match for publishing
6+
- 'v[0-9]+.[0-9]+.[0-9]+*'
7+
8+
permissions:
9+
contents: write
10+
id-token: write # Required for OIDC authentication
711

812
jobs:
9-
publish:
13+
release:
14+
name: Release and Publish
1015
runs-on: ubuntu-latest
11-
permissions:
12-
id-token: write # Required for authentication using OIDC
13-
contents: write
1416
steps:
15-
- name: Checkout repository
17+
- name: Checkout code
1618
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
1721

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

28-
- name: Setup Dart for publishing
32+
- name: Setup Dart
2933
uses: dart-lang/setup-dart@v1
3034
with:
3135
sdk: ${{ steps.asdf.outputs.dart }}
3236

33-
- name: Setup Melos
37+
- name: Set environment
38+
run: echo "$HOME/.pub-cache/bin" >> "$GITHUB_PATH"
39+
40+
- name: Setup Bun
41+
uses: oven-sh/setup-bun@v1
42+
with:
43+
bun-version: ${{ steps.asdf.outputs.bun }}
44+
45+
- name: Install Melos
3446
run: dart pub global activate melos
3547

36-
- name: Get Melos packages
37-
run: melos bootstrap
48+
- name: Bootstrap packages
49+
run: |
50+
melos bootstrap
51+
bun install
3852
39-
- name: Publish package
40-
run: dart pub publish --force
53+
- name: Verify all tests pass
54+
run: melos test
55+
56+
- name: Verify code formatting
57+
run: melos format && melos analyze
58+
59+
- name: Check package can be published (dry-run)
60+
run: dart pub publish --dry-run
61+
62+
- name: Generate release notes
63+
id: release_notes
64+
uses: orhun/git-cliff-action@v3
65+
with:
66+
config: .github/cliff.toml
67+
args: --latest --strip header
4168

4269
- name: Create GitHub Release
43-
uses: softprops/action-gh-release@v2 # Consider using a more recent version
44-
if: startsWith(github.ref, 'refs/tags/')
70+
uses: softprops/action-gh-release@v2
4571
env:
4672
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
73+
with:
74+
tag_name: ${{ github.ref_name }}
75+
name: ${{ github.ref_name }}
76+
body: ${{ steps.release_notes.outputs.content }}
77+
draft: false
78+
prerelease: false
79+
80+
- name: Publish to pub.dev
81+
run: dart pub publish --force

.husky/pre-commit

Lines changed: 0 additions & 5 deletions
This file was deleted.

CLAUDE.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
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.
8+
9+
## Development Commands
10+
11+
### Essential Commands
12+
13+
```bash
14+
# Install dependencies
15+
melos get
16+
bun install
17+
18+
# Run tests
19+
melos test
20+
21+
# Run code analysis
22+
melos analyze
23+
24+
# Format code (Dart + Prettier)
25+
melos format
26+
27+
# Run all checks (analyze + format + test)
28+
melos analyze && melos format && melos test
29+
30+
# Run a single test file
31+
flutter test test/flutter_hooks_test_test.dart
32+
33+
# Run tests with coverage
34+
flutter test --coverage
35+
```
36+
37+
### Additional Commands
38+
39+
```bash
40+
# Upgrade dependencies
41+
melos upgrade
42+
43+
# Clean build artifacts
44+
melos clean
45+
46+
# Format with Prettier only
47+
bun run format
48+
49+
# Setup git hooks
50+
bun run prepare
51+
```
52+
53+
## Architecture and Code Structure
54+
55+
### Core API
56+
57+
The library exports a single file `lib/flutter_hooks_test.dart` containing:
58+
59+
1. **`buildHook<T, P>`** - Main function to test hooks
60+
- Generic `T`: Return type of the hook
61+
- Generic `P`: Props type for parameterized hooks
62+
- Returns `_HookTestingAction<T>` with methods:
63+
- `current`: Access current hook value
64+
- `rebuild([props])`: Trigger rebuild with optional new props
65+
- `unmount()`: Unmount the hook
66+
67+
2. **`act`** - Wraps state changes to ensure proper Flutter test lifecycle
68+
- Similar to React's `act` function
69+
- Required when changing hook state
70+
71+
### Testing Pattern
72+
73+
```dart
74+
// Basic hook test structure
75+
final result = await buildHook((_) => useMyHook());
76+
await act(() => result.current.doSomething());
77+
expect(result.current.value, expectedValue);
78+
79+
// With wrapper widget
80+
final result = await buildHook(
81+
(_) => useMyHook(),
82+
wrapper: (child) => Provider(child: child),
83+
);
84+
```
85+
86+
### Internal Implementation
87+
88+
- Uses `TestWidgetsFlutterBinding` for test environment
89+
- Creates a minimal widget tree with `HookBuilder`
90+
- Manages completer-based async operations for mount/unmount
91+
- Preserves hook state across rebuilds using keys
92+
93+
## Testing Approach
94+
95+
- All tests go in `test/` directory
96+
- Example hooks in `test/hooks/` demonstrate testable patterns
97+
- Use `testWidgets` for widget-based tests
98+
- Use Mockito for mocking dependencies
99+
100+
## Code Quality
101+
102+
- Flutter lints are enforced via `analysis_options.yaml`
103+
- Example directory is excluded from analysis
104+
- Pre-commit hooks format code automatically
105+
- CI runs on Ubuntu with asdf version management
106+
107+
## Important Conventions
108+
109+
1. **Type Safety**: Always specify generic types when using `buildHook`
110+
2. **Act Wrapper**: Always wrap state changes in `act()`
111+
3. **Async Handling**: Most operations return Futures - use `await`
112+
4. **Testing**: Test both happy paths and edge cases (mount/unmount/rebuild)
113+
114+
## Version Requirements
115+
116+
- Dart SDK: `>=2.17.0 <4.0.0`
117+
- Flutter: `>=3.20.0`
118+
- Uses Flutter hooks `^0.21.2`
119+
120+
## Release Process
121+
122+
Releases are fully automated via GitHub Actions:
123+
124+
### Creating a Release
125+
126+
1. **Update version**: Update version in `pubspec.yaml`
127+
2. **Update changelog**: Run `git cliff --unreleased --tag v1.0.1 --output CHANGELOG.md`
128+
3. **Commit changes**: `git commit -am "chore(release): prepare for v1.0.1"`
129+
4. **Create tag**: `git tag v1.0.1`
130+
5. **Push**: `git push origin main --tags`
131+
132+
### Automated Release Steps
133+
134+
When a tag matching `v[0-9]+.[0-9]+.[0-9]+*` is pushed:
135+
136+
1. **CI Validation**: All tests, formatting, and analysis must pass
137+
2. **Dry Run**: Package publication is tested
138+
3. **Release Notes**: Auto-generated using git-cliff from conventional commits
139+
4. **GitHub Release**: Created with generated release notes
140+
5. **pub.dev Publication**: Package is published automatically
141+
142+
### Commit Convention
143+
144+
Use [Conventional Commits](https://www.conventionalcommits.org/) for automatic release note generation:
145+
146+
- `feat:` - New features
147+
- `fix:` - Bug fixes
148+
- `docs:` - Documentation changes
149+
- `test:` - Test improvements
150+
- `refactor:` - Code refactoring
151+
- `perf:` - Performance improvements

0 commit comments

Comments
 (0)