test(search): add NL search happy-path Playwright E2E (#739)
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m17s
CI / OCR Service Tests (pull_request) Successful in 22s
CI / Backend Unit Tests (pull_request) Successful in 3m47s
CI / fail2ban Regex (pull_request) Successful in 46s
CI / Semgrep Security Scan (pull_request) Successful in 24s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m6s
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m17s
CI / OCR Service Tests (pull_request) Successful in 22s
CI / Backend Unit Tests (pull_request) Successful in 3m47s
CI / fail2ban Regex (pull_request) Successful in 46s
CI / Semgrep Security Scan (pull_request) Successful in 24s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m6s
Mock POST /api/search/nl (delayed fixture: 2-name directional + applied keyword), assert loading announcement → chips render → axe-clean in light and dark → removing the keyword chip re-runs a keyword GET with the remaining sender+receiver params. Adds a data-testid wrapper on the NL results region for axe scoping. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -422,48 +422,50 @@ $effect(() => {
|
||||
|
||||
{#if showNlView}
|
||||
<!-- Smart-search results area: loading / error / chips + results / empty / disambiguation. -->
|
||||
{#if nlLoading}
|
||||
<SmartSearchStatus status="loading" />
|
||||
{:else if nlError}
|
||||
<SmartSearchStatus
|
||||
status="error"
|
||||
errorCode={nlError}
|
||||
onSwitchToKeyword={switchToKeywordMode}
|
||||
/>
|
||||
{:else if nlInterpretation}
|
||||
{#key nlInterpretation}
|
||||
<div class="mb-4">
|
||||
{#if nlIsAmbiguous}
|
||||
<DisambiguationPicker
|
||||
persons={nlInterpretation.ambiguousPersons}
|
||||
onSelect={selectDisambiguated}
|
||||
/>
|
||||
{:else}
|
||||
<InterpretationChipRow interpretation={nlInterpretation} onRemoveChip={removeChip} />
|
||||
{/if}
|
||||
</div>
|
||||
<div data-testid="smart-search-results">
|
||||
{#if nlLoading}
|
||||
<SmartSearchStatus status="loading" />
|
||||
{:else if nlError}
|
||||
<SmartSearchStatus
|
||||
status="error"
|
||||
errorCode={nlError}
|
||||
onSwitchToKeyword={switchToKeywordMode}
|
||||
/>
|
||||
{:else if nlInterpretation}
|
||||
{#key nlInterpretation}
|
||||
<div class="mb-4">
|
||||
{#if nlIsAmbiguous}
|
||||
<DisambiguationPicker
|
||||
persons={nlInterpretation.ambiguousPersons}
|
||||
onSelect={selectDisambiguated}
|
||||
/>
|
||||
{:else}
|
||||
<InterpretationChipRow interpretation={nlInterpretation} onRemoveChip={removeChip} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if !nlIsAmbiguous}
|
||||
{#if nlHasResults}
|
||||
<p class="mb-3 font-sans text-base text-ink-2">
|
||||
{m.docs_result_count({ count: nlResult?.totalElements ?? 0 })}
|
||||
</p>
|
||||
<DocumentList items={nlResult?.items ?? []} canWrite={data.canWrite} sort={sort} />
|
||||
{:else}
|
||||
<div class="flex flex-col items-center justify-center gap-3 py-16 text-center">
|
||||
<p class="text-sm font-bold text-ink">{m.search_empty_nl()}</p>
|
||||
<button
|
||||
type="button"
|
||||
onclick={switchToKeywordMode}
|
||||
class="inline-flex min-h-[44px] items-center rounded px-3 py-2 text-sm font-bold text-primary underline underline-offset-4 outline-none hover:text-brand-mint focus-visible:ring-2 focus-visible:ring-brand-navy"
|
||||
>
|
||||
{m.search_empty_retry_keyword()}
|
||||
</button>
|
||||
</div>
|
||||
{#if !nlIsAmbiguous}
|
||||
{#if nlHasResults}
|
||||
<p class="mb-3 font-sans text-base text-ink-2">
|
||||
{m.docs_result_count({ count: nlResult?.totalElements ?? 0 })}
|
||||
</p>
|
||||
<DocumentList items={nlResult?.items ?? []} canWrite={data.canWrite} sort={sort} />
|
||||
{:else}
|
||||
<div class="flex flex-col items-center justify-center gap-3 py-16 text-center">
|
||||
<p class="text-sm font-bold text-ink">{m.search_empty_nl()}</p>
|
||||
<button
|
||||
type="button"
|
||||
onclick={switchToKeywordMode}
|
||||
class="inline-flex min-h-[44px] items-center rounded px-3 py-2 text-sm font-bold text-primary underline underline-offset-4 outline-none hover:text-brand-mint focus-visible:ring-2 focus-visible:ring-brand-navy"
|
||||
>
|
||||
{m.search_empty_retry_keyword()}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
{/key}
|
||||
{/if}
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="mt-3 mb-4 hidden lg:block">
|
||||
<TimelineDensityFilter
|
||||
|
||||
Reference in New Issue
Block a user