fix: SearchPanel test の full-suite 限定 timeout を実描画量の削減で解消する - #507
Open
ymnao wants to merge 4 commits into
Open
Conversation
- 実測で主因を特定した。単体実行でも当該 file は tests 6.91s あり、内訳は 「さらに表示」click + 700 行再描画が 530ms、debounce 300ms + 500 行描画が 390ms。フルスイートの CPU 競合下でこの CPU バウンド分が数倍に伸びて testTimeout (5s) に届いていた - MATCH_DISPLAY_STEP を types/search.ts へ移した。SearchPanel.tsx 内に置いた ままではテストが定数だけを差し替えられない (component file を vi.mock すると SearchPanel 自体がモックされる)。依存の末端である types へ動かして部分モック 可能にした。置き場所も MAX_SEARCH_RESULTS と揃う - テストは step=5 を注入し、件数を 7 / 6 / 15 系へ。リセット test の 「初期値 5 < 新検索 7 <= stale 値 10」の狭間関係は保存している - 期待値は変数ではなく literal にした。変数だと注入が効かなくなったとき 500 に追随して黙って pass し、再発が観測に出ない - 兄弟 panel の idiom に合わせて fake timer 化し waitFor を撤去した。 .then 経路があるので advanceTimersByTimeAsync を使う - 実値 500 は vi.importActual でモックを迂回して 1 本 pin した
- 件数を裸の literal (7 / 6 / 15) にしたことで、STEP との関係が式から消えて いた。特にリセット test の「2 回目の総件数を初期値と stale 値の狭間に置く」 という要は、15 / 10 / 7 の並びからは読み取れなくなっていた - vi.hoisted で test 固有の STEP を 1 箇所に置き、mock 注入と入力件数の 両方をそこから導く。手動同期の余地を無くす - STEP は test 固有なので production の 500 に追随しない。よって期待値にも STEP を使ってよく、literal に固定する必要が無くなった。根拠が変わったので コメントも「import しない理由」へ書き換えた - 1 テストだけの describe を外して top-level it にした
- 「初期値と stale 値の狭間に置く」と書いたが、上限は判別性に寄与しない。 総件数 15 でもリセット欠落時は 10 件描画で toHaveLength(STEP) は落ちる。 区別できなくなるのは総件数が STEP 以下のときだけなので、必要条件は 「STEP より大きい」だけ。設計判断の根拠として引用されると誤るので直す - MATCH_DISPLAY_STEP に「IPC 境界をまたがない renderer 専用値」であることと 「なぜ SearchPanel.tsx ではなくここに居るか」を書いた。隣の MAX_SEARCH_RESULTS が IPC 共有値の置き場としてこの module を枠付けて いるため、注記が無いと main 側から流用される余地が残る - 件数表示の期待文字列も STEP から導出し、手動同期の残りを無くした
- 「component file を vi.mock するとコンポーネント自体がモックされる」と 書いたが、これは factory 無しの auto-mock でしか真でない。importOriginal を 併用する実際の書き方ではコンポーネントはモックされない - probe で実測した (定数と、それを読む関数を持つ module を partial mock): export は 5 に差し替わる一方、module 内部の関数が読む値は 500 のまま、 関数自身はモックされていない。差し替えが効かない真因はこちら - 誤った理由を残すと「partial mock なら定数だけ差し替えられる」という 代替案の再提案を招くので、実測した機構に置き換えた - 独立した 2 つの Why not の間に空行を入れた
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
SearchPanel.test.tsxの段階表示 test がフルスイート実行時のみ間欠的に testTimeout する問題 (#501) を、timeout を伸ばさず実描画量を落とす方向で解消した。実測で主因を特定した結果、単体実行でも当該 file は tests 6.91s かかっており、内訳は次のとおりだった(
performance.now()の probe で計測、probe は削除済み)。支配項は 描画件数そのもの(CPU バウンド)、次いで fake timer 非使用による実時間 debounce 300ms。フルスイートの並列実行で CPU が競合すると、この CPU バウンド分が数倍に伸びて既定の testTimeout (5s) に届いていた。
関連 Issue
closes #501
移行 Stage
変更内容
MATCH_DISPLAY_STEPをsrc/types/search.tsへ移設した。使用元のSearchPanel.tsxに置いたままではテストが定数だけを差し替えられない。理由は実測で確認した: 定数とそれを読む関数を持つ module をvi.mock+importOriginalで partial mock すると、export は差し替わるが module 内部の参照は元の値を読み続ける(関数自身はモックされない)。production の値は 500 のまま、外形 API も不変vi.hoistedのSTEP(=5) を 注入値と入力件数の単一の出所にした。件数はSTEP + 2/STEP + 1/STEP * 3と関係式で表し、手動同期の余地を無くしているBacklinkPanel/UnresolvedLinksPanel) の idiom に合わせて fake timer 化しwaitForを撤去した。.then経路があるのでadvanceTimersByTimeAsyncを使うvi.importActualでモックを迂回して 1 本 pin した(ユニット総数 3165 → 3166)動作確認
SearchPanel.tsxの差分は import 1 行のみ、定数値も 500 のまま)検証エビデンス
リスク分類
tier: medium — reasons: (
classify-risk.shの出力は{"tier": "medium", "reasons": []}で、理由列挙は空)実行した検証
vitest run --project renderer src/components/search/SearchPanel.test.tsxenv -u GIT_CONFIG_* vitest runbiome check src/ electron/tsc --noEmit -p tsconfig.node.json/tsconfig.web.json/tsconfig.e2e.jsonelectron-vite build✓ built in 469ms、警告は既存の INEFFECTIVE_DYNAMIC_IMPORT のみ)e2e3m21s /electron-e2e1m2s)CI は全 9 job pass(
lint25s /typecheck28s /test1m24s /e2e3m21s /electron-e2e1m2s /build25s /dependency-review4s /win32-fs-probe49s /Analyze (javascript-typescript)1m2s)。mutation 検証
types/search.tsの 500 → 499SearchPanel.tsxの.then内setVisibleCount(MATCH_DISPLAY_STEP)を削除MATCH_DISPLAY_STEPの注入を外すactual.MATCH_DISPLAY_STEPに差し替え(注入無効化)3・4 番目が「注入が効かなくなったら必ず落ちる(silent pass しない)」性質を pin している。
レビュー指摘と対応
436f6c0)。総件数 15 でもリセット欠落時は 10 件描画でtoHaveLength(STEP)は落ちるため、必要条件は「STEP より大きい」だけMATCH_DISPLAY_STEPが IPC 共有値と誤読されうる(Altitude レビューと独立に収束)436f6c0)。「IPC 境界をまたがない renderer 専用値」であることと配置理由を注記436f6c0)。STEPから導出aa1ba51)。probe で実測し(export は 5 に差し替わるが module 内部は 500 を読み、関数はモックされない)、実測した機構に書き直した75ca6ee)truncated: true+ 少件数 fixture が production では実現不能追跡先
backlog delta: 起票 0 件 / 本 PR で close 1 件(#501)/ 現在 open 13 件
src/components/search/SearchPanel.tsx:117— 「さらに表示」で表示済み行も再描画onNavigateの identity 安定化が要り、「production 挙動は不変」という本 PR の柱を崩してレビュー範囲を広げるため見送り。実測値 530ms は commit13ef95aに残るEmojiInputDialog/SlideView/MarkdownEditor/slide-render— 高負荷下で testTimeoutDraft 判定