Skip to content
Open
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
148 changes: 148 additions & 0 deletions BUG_REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Bug Report & Test Results

## Test Results Summary

### ✅ All Tests Passing
All 13 test cases pass successfully in both environments:
- **Happy-DOM environment**: ✓ 13/13 tests passed
- **Vitest Browser Mode (Firefox)**: ✓ 13/13 tests passed

### Test Coverage

The test suite comprehensively covers all README use cases:

1. **Basic hoisting functionality**
- ✓ Content hoists from `<Hoist>` to `<Slot>`
- ✓ Multiple hoisted elements render correctly

2. **Priority-based ordering**
- ✓ Elements with lower priority values render first
- ✓ Same priority elements maintain insertion order
- ✓ Mixed priorities work as documented in README

3. **Multiple independent hoisting systems**
- ✓ Different hoisting instances maintain separate state

4. **Conditional hoisting**
- ✓ Content shows/hides based on conditions

5. **Edge cases**
- ✓ Default priority (0) works correctly
- ✓ Empty slot renders nothing
- ✓ Proper error handling without Provider

6. **Dynamic updates**
- ✓ Content updates when children change
- ✓ Order updates when priority changes

## Potential Issues Found

While all tests pass, code review revealed potential improvements:

### 1. TypeScript Type Safety Issue (Minor)

**Location**: `lib/src/create-hoistable-component.tsx:149`

```tsx
// Current implementation
const keyRef = useRef<symbol>(null);
```

**Issue**:
- `useRef<symbol>` expects a `symbol` type, but `null` is provided as initial value
- TypeScript infers this as `useRef<symbol | null>` which may cause type inconsistencies
- The code compensates with runtime checks, but the type annotation is misleading

**Recommended fix**:
```tsx
// Option 1: Explicit nullable type
const keyRef = useRef<symbol | null>(null);

// Option 2: Initialize with Symbol (preferred)
const keyRef = useRef<symbol>(Symbol("hoist-entry"));
```

If using Option 2, remove the conditional assignment (lines 151-153) and directly use `keyRef.current` since it's always defined.

### 2. Performance Consideration

**Location**: `lib/src/create-hoistable-component.tsx:166`

```tsx
useEffect(() => {
// ...
}, [children, priority, upsert, remove]);
```

**Observation**:
- `children` is included in the dependency array
- In React, `children` creates a new reference on every render, potentially causing unnecessary updates
- However, this is actually correct behavior for this use case, as we want to update the hoisted content when children change

**Status**: Not a bug, working as intended

### 3. Implementation Verification

The sorting logic was verified and is **correct**:

```tsx
return newEntries.sort((a, b) => {
// Primary sort: priority (lower numbers first)
const priorityDiff = a.priority - b.priority;
if (priorityDiff !== 0) {
return priorityDiff; // ✓ Correct: lower numbers first
}
// Secondary sort: insertion order via keyId (stable sort)
return a.keyId.localeCompare(b.keyId, undefined, { numeric: true }); // ✓ Correct
});
```

## Conclusion

### Bug Status
**No critical bugs found.** The implementation works correctly as documented in the README.

### Recommendations

1. **Fix TypeScript type annotation** (Line 149) for better type safety
2. Consider adding the fix to improve code clarity:

```tsx
// Before
const keyRef = useRef<symbol>(null);
if (!keyRef.current) {
keyRef.current = Symbol("hoist-entry");
}

// After (recommended)
const keyRef = useRef<symbol>(Symbol("hoist-entry"));
```

This change:
- Eliminates the null check
- Improves type safety
- Makes the code clearer
- Has no functional impact (behavior remains the same)

### Test Infrastructure Improvements

The PR includes:
- ✅ Comprehensive test suite with 13 test cases
- ✅ Vitest Browser Mode configuration (Firefox for ARM compatibility)
- ✅ Tests cover all documented README use cases
- ✅ Both unit and integration-style tests

### Configuration Notes

For Vitest Browser Mode to work:
1. Install: `@vitest/browser`, `@vitest/browser-playwright`, `playwright`
2. Configure `vitest.config.ts` with browser instances
3. Use Firefox on ARM architecture (Chromium not supported)
4. Run tests with: `bunx vitest run` (not `bun test`)

## Next Steps

If you want to apply the type safety fix, create a PR with:
1. Fix the TypeScript type annotation in `create-hoistable-component.tsx:149`
2. Include the comprehensive test suite
3. Document the browser mode setup for ARM environments
182 changes: 182 additions & 0 deletions PULL_REQUEST_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# PR: Add Comprehensive Test Suite & Fix TypeScript Type Safety

## 概要

このPRでは、Vitest Browser Reactを使用したE2Eスタイルのテストスイートを実装し、TypeScriptの型安全性の問題を修正しました。

## 実装内容

### 1. テストスイート追加 (`lib/src/create-hoistable-component.test.tsx`)

READMEに記載されている全てのユースケースをカバーする包括的なテストスイートを実装:

- **基本的なHoist機能** (2テスト)
- `<Hoist>`から`<Slot>`へのコンテンツの移動
- 複数のHoist要素の同時レンダリング

- **優先度ベースのソート** (3テスト)
- 小さい優先度値が先にレンダリングされることの検証
- 同じ優先度の要素が挿入順序を維持することの検証
- README記載の実例の動作確認

- **複数の独立したHoistingシステム** (1テスト)
- 異なるHoistingインスタンスが独立した状態を維持

- **条件付きHoisting** (1テスト)
- 条件に基づくコンテンツの表示/非表示

- **エッジケース** (4テスト)
- デフォルト優先度(0)の動作
- 空のSlotの動作
- Providerなしでの適切なエラーハンドリング

- **動的更新** (2テスト)
- childrenの変更時のコンテンツ更新
- 優先度変更時の順序更新

**テスト結果**: ✅ 13/13 テスト全てパス

### 2. Vitest Browser Mode設定

ARM環境でも動作するように、Firefoxを使用したブラウザモードを設定:

- `vitest.config.ts`をブラウザモード対応に更新
- Playwright providerの設定(Vitest v4の新しいAPI使用)
- Firefox使用(ARM環境での互換性)

**依存関係追加**:
```json
{
"@vitest/browser": "^4.0.15",
"@vitest/browser-playwright": "^4.0.15",
"playwright": "^1.57.0",
"react": "^19.2.1",
"react-dom": "^19.2.1"
}
```

### 3. TypeScript型安全性の修正

**問題箇所**: `lib/src/create-hoistable-component.tsx:149`

#### 修正前
```tsx
const keyRef = useRef<symbol>(null);

if (!keyRef.current) {
keyRef.current = Symbol("hoist-entry");
}

useEffect(() => {
if (!keyRef.current) {
return;
}
upsert(keyRef.current, children, priority);
return () => {
if (!keyRef.current) {
return;
}
remove(keyRef.current);
};
}, [children, priority, upsert, remove]);
```

**問題点**:
- `useRef<symbol>`に`null`を渡しているため、型が不整合
- 不要なnullチェックが複数箇所に存在
- TypeScriptの型システムを適切に活用できていない

#### 修正後
```tsx
const keyRef = useRef<symbol>(Symbol("hoist-entry"));

useEffect(() => {
upsert(keyRef.current, children, priority);
return () => {
remove(keyRef.current);
};
}, [children, priority, upsert, remove]);
```

**改善点**:
- ✅ 型安全性の向上(`symbol`型が常に保証される)
- ✅ 不要なnullチェックの削除(コードが簡潔に)
- ✅ 動作は完全に同一(破壊的変更なし)

## テスト環境

### ローカル環境
- **OS**: Linux (ARM64)
- **ブラウザ**: Firefox (Playwrightによる自動実行)
- **テストランナー**: Vitest v4.0.15
- **実行コマンド**: `bunx vitest run`

### 注意事項
⚠️ `bun test`ではなく`bunx vitest run`を使用してください
- `bun test`はBunのネイティブテストランナーを使用するため、Vitestの設定が適用されません

## 検証結果

### バグ調査結果
- ✅ READMEの全ユースケースが正しく機能していることを確認
- ✅ 優先度のソートロジックが仕様通り動作
- ✅ 挿入順序の保持が正しく実装されている
- ✅ 複数のHoistingシステムが独立して動作

### 発見された問題
- TypeScriptの型注釈の不整合(修正済み)
- 他の機能的なバグは発見されず

## Breaking Changes

なし。型の修正は内部実装の改善のみで、公開APIに変更はありません。

## 今後の推奨事項

1. **CI/CDへの統合**: GitHub Actionsでブラウザテストを自動実行
2. **カバレッジ測定**: テストカバレッジの測定と可視化
3. **パフォーマンステスト**: 大量の要素を使用した際のパフォーマンス検証

## ファイル変更リスト

### 追加
- `lib/src/create-hoistable-component.test.tsx` - テストスイート(新規)
- `BUG_REPORT.md` - 詳細な調査結果
- `PULL_REQUEST_SUMMARY.md` - このファイル

### 変更
- `lib/src/create-hoistable-component.tsx` - 型安全性の修正
- `lib/vitest.config.ts` - ブラウザモード設定
- `lib/package.json` - 依存関係追加

### 設定変更
- Vitest Browser Mode (Firefox)
- Playwright provider設定

## 実行方法

```bash
# テスト実行(ブラウザモード)
cd lib
bunx vitest run

# ウォッチモード
bunx vitest

# TypeScriptチェック
bun run typecheck

# ビルド
bun run build
```

## レビューポイント

1. テストケースがREADMEの全ユースケースをカバーしているか
2. TypeScript型の修正が適切か
3. ブラウザモードの設定が環境に依存しすぎていないか
4. テストの実行時間が許容範囲内か(現在約4秒)

---

**テスト結果**: ✅ All 13 tests passing in Firefox browser mode
Loading
Loading