# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: ncjs-screen-state-compare.checks.spec.ts >> 画面状態JSONをExpectedと比較してDiffを保存できる
- Location: tests\screen_state\ncjs-screen-state-compare.checks.spec.ts:255:5

# Error details

```
Error: expect(received).toBe(expected) // Object.is equality

Expected: "pass"
Received: "fail"
```

# Page snapshot

```yaml
- generic [active] [ref=e1]:
  - banner [ref=e2]:
    - generic [ref=e3]:
      - generic [ref=e4]: FRB Studio
      - heading "JSON Object Studio v0.4-r001" [level=1] [ref=e5]:
        - generic [ref=e6]: JSON Object Studio
        - generic [ref=e7]: v0.4-r001
      - paragraph [ref=e8]: JSONで思考を構造化し、AIとの文脈を育てる。
    - region "JSON読み込み" [ref=e9]:
      - generic [ref=e10]:
        - generic [ref=e11]: 画面定義JSON
        - generic [ref=e12]:
          - textbox "画面定義JSON 画面定義JSONの場所をExplorerで開く 画面定義JSONの選択をクリア ▾" [ref=e13]:
            - /placeholder: defs から検索・選択
          - button "画面定義JSONの場所をExplorerで開く" [disabled] [ref=e14]: 📁
          - button "画面定義JSONの選択をクリア": ×
          - text: ▾
      - generic [ref=e15]:
        - generic [ref=e16]: 対象JSON
        - generic [ref=e17]:
          - textbox "対象JSON 対象JSONの場所をExplorerで開く 対象JSONの選択をクリア ▾" [ref=e18]:
            - /placeholder: data から検索・選択
          - button "対象JSONの場所をExplorerで開く" [disabled] [ref=e19]: 📁
          - button "対象JSONの選択をクリア": ×
          - text: ▾
      - generic [ref=e20] [cursor=pointer]:
        - generic [ref=e21]: 定義Drop
        - generic [ref=e22]: Drop
      - generic [ref=e23] [cursor=pointer]:
        - generic [ref=e24]: 対象Drop
        - generic [ref=e25]: Drop
      - button "読み込み" [ref=e26] [cursor=pointer]
      - button "保存" [disabled] [ref=e27]
      - generic "Viewerリンク" [ref=e28]:
        - generic "Viewerリンク" [ref=e29]:
          - generic [ref=e30]: Viewer
          - link "📝 Markdown Viewer" [ref=e31] [cursor=pointer]:
            - /url: mdViewer.html
            - generic [ref=e32]: 📝
            - generic [ref=e33]:
              - generic [ref=e34]: Markdown
              - generic [ref=e35]: Viewer
          - link "Δ DiffJSON 差分Viewer" [ref=e36] [cursor=pointer]:
            - /url: DiffJsonViewer.html
            - generic [ref=e37]: Δ
            - generic [ref=e38]:
              - generic [ref=e39]: DiffJSON
              - generic [ref=e40]: 差分Viewer
          - link "🧠 MetaDiff AI差分仮説" [ref=e41] [cursor=pointer]:
            - /url: MetaDiff_HypothesisViewer.html
            - generic [ref=e42]: 🧠
            - generic [ref=e43]:
              - generic [ref=e44]: MetaDiff
              - generic [ref=e45]: AI差分仮説
      - generic "Markdown出力" [ref=e46]:
        - generic "Markdown出力" [ref=e47]:
          - generic [ref=e48]: Output
          - generic "Markdown出力モード" [ref=e49]:
            - button "MD 出力→Viewer" [disabled] [ref=e50]:
              - generic [ref=e51]: MD
              - generic [ref=e52]: 出力→Viewer
            - combobox "Markdown出力モード" [disabled] [ref=e53]:
              - option "レビュー用" [selected]
              - option "全項目"
          - button "ViewDef 出力→Viewer" [disabled] [ref=e54]:
            - generic [ref=e55]: ViewDef
            - generic [ref=e56]: 出力→Viewer
    - generic "現在表示中のData JSON" [ref=e57]:
      - 'generic "一覧を更新しました: defs 54件 / data 58件" [ref=e58]'
  - main [ref=e59]
```

# Test source

```ts
  270 | 
  271 |   const checks = pattern.checks.map(check => evaluateCheck(check, state));
  272 |   const total = checks.length;
  273 |   const passCount = checks.filter(check => check.pass).length;
  274 |   const failCount = total - passCount;
  275 |   const failedChecks = checks.filter(check => !check.pass);
  276 |   const status = failedChecks.length === 0 ? 'pass' : 'fail';
  277 |   const firstFailure = failedChecks[0] ?? null;
  278 |   const capturedAt = new Date().toISOString();
  279 | 
  280 |   const expectedFile = requireRelativeFile(testPattern.expectedFile, 'expectedFile');
  281 |   const outputActualFile = requireRelativeFile(testPattern.outputActualFile, 'outputActualFile');
  282 |   const outputDiffFile = requireRelativeFile(testPattern.outputDiffFile, 'outputDiffFile');
  283 |   const testId = pattern.testId || TEST_ID;
  284 |   const failedCheckIds = failedChecks.map(check => check.check_id);
  285 |   const failedCheckNames = failedChecks.map(check => check.name);
  286 | 
  287 |   const emphasizedDiff = {
  288 |     view_def: testPattern.diffViewDef || DIFF_VIEW_DEF,
  289 |     schema_version: 'diff_result_v0_1',
  290 |     document_type: 'diff_result',
  291 |     domain: 'screen_state',
  292 |     diff_kind: 'screen_state_smoke',
  293 |     test_id: testId,
  294 |     testId,
  295 |     test_name: pattern.title,
  296 |     title: pattern.title,
  297 |     generated_at: capturedAt,
  298 |     capturedAt,
  299 |     url: BASE_URL,
  300 |     status,
  301 |     resultLabel: status === 'pass' ? '✅ PASS' : '🚨 FAIL',
  302 |     summary: failedChecks.length === 0
  303 |       ? '✅ 差分は検出されませんでした。'
  304 |       : `🚨 ${failedChecks.length}件の差分を検出しました: ${failedCheckIds.join(', ')}`,
  305 |     total,
  306 |     passCount,
  307 |     failCount,
  308 |     failedCount: failedChecks.length,
  309 |     failedChecks: failedCheckNames,
  310 |     failedCheckIds,
  311 |     firstFailure: firstFailure
  312 |       ? {
  313 |           check_id: firstFailure.check_id,
  314 |           name: firstFailure.name,
  315 |           type: firstFailure.type,
  316 |           target: firstFailure.target,
  317 |           expected: firstFailure.expected,
  318 |           actual: firstFailure.actual,
  319 |           missing: firstFailure.missing
  320 |         }
  321 |       : null,
  322 |     result_summary: {
  323 |       total_count: total,
  324 |       pass_count: passCount,
  325 |       fail_count: failCount,
  326 |       total,
  327 |       passCount,
  328 |       failCount
  329 |     },
  330 |     sourceFiles: {
  331 |       testPatternFile: TEST_PATTERN_REGISTRY_FILE,
  332 |       expectedFile,
  333 |       actualFile: outputActualFile,
  334 |       diffFile: outputDiffFile,
  335 |       outputActualFile,
  336 |       outputDiffFile
  337 |     },
  338 |     checks,
  339 |     actualState: state
  340 |   };
  341 | 
  342 |   const actualPath = resolveProjectFile(outputActualFile);
  343 |   const diffPath = resolveProjectFile(outputDiffFile);
  344 | 
  345 |   fs.mkdirSync(path.dirname(actualPath), { recursive: true });
  346 |   fs.mkdirSync(path.dirname(diffPath), { recursive: true });
  347 | 
  348 |   fs.writeFileSync(actualPath, JSON.stringify({
  349 |     view_def: pattern.view_def || testPattern.expectedViewDef || 'screen_state/screen_state_expected_view_def_v0_1.json',
  350 |     schema_version: 'screen_state_actual_v0_1',
  351 |     document_type: 'screen_state_actual',
  352 |     testId: pattern.testId || TEST_ID,
  353 |     title: pattern.title,
  354 |     capturedAt,
  355 |     sourceFiles: {
  356 |       testPatternFile: TEST_PATTERN_REGISTRY_FILE,
  357 |       expectedFile,
  358 |       outputActualFile,
  359 |       outputDiffFile
  360 |     },
  361 |     state
  362 |   }, null, 2), 'utf8');
  363 | 
  364 |   fs.writeFileSync(diffPath, JSON.stringify(emphasizedDiff, null, 2), 'utf8');
  365 |   // actual/diff は data/json/03_tests 配下を正本とする。
  366 |   // Playwright attachment は長い実行結果パスを生成するため、ここでは作成しない。
  367 | 
  368 |   removeEmptyLegacyTestsScreenStateDir();
  369 | 
> 370 |   expect(emphasizedDiff.status).toBe('pass');
      |                                 ^ Error: expect(received).toBe(expected) // Object.is equality
  371 | 
  372 | });
  373 | 
```