diff --git a/src/components/article-input-form.tsx b/src/components/article-input-form.tsx index 49b0440..4d62a69 100644 --- a/src/components/article-input-form.tsx +++ b/src/components/article-input-form.tsx @@ -1,6 +1,6 @@ "use client"; -import type { FormEvent } from "react"; +import type { Dispatch, FormEvent, SetStateAction } from "react"; import type { PublishPlatform } from "../lib/domain/types"; @@ -15,7 +15,7 @@ export interface ArticleInputPayload { interface ArticleInputFormProps { value: ArticleInputPayload; isSubmitting: boolean; - onChange: (value: ArticleInputPayload) => void; + onChange: Dispatch>; onSubmit: () => void; } @@ -36,7 +36,7 @@ export function ArticleInputForm({ key: K, nextValue: ArticleInputPayload[K], ) { - onChange({ ...value, [key]: nextValue }); + onChange((current) => ({ ...current, [key]: nextValue })); } function handleSubmit(event: FormEvent) { diff --git a/src/lib/cases/types.ts b/src/lib/cases/types.ts index 423fc52..1f1d90b 100644 --- a/src/lib/cases/types.ts +++ b/src/lib/cases/types.ts @@ -65,7 +65,7 @@ export interface ArticleCaseInputPayload { fact_card?: unknown; } -export interface HumanCopyCaseInputPayload extends CopyOptimizationRequest {} +export type HumanCopyCaseInputPayload = CopyOptimizationRequest; export interface ArticleResultVersionPayload { article: OptimizedArticle; @@ -73,7 +73,7 @@ export interface ArticleResultVersionPayload { export_paths: Record; } -export interface HumanCopyResultVersionPayload extends CopyOptimizationResult {} +export type HumanCopyResultVersionPayload = CopyOptimizationResult; export interface OptimizationResultVersion { id: string; diff --git a/src/lib/db/d1-repository.ts b/src/lib/db/d1-repository.ts index 7651ed5..8916e57 100644 --- a/src/lib/db/d1-repository.ts +++ b/src/lib/db/d1-repository.ts @@ -7,8 +7,6 @@ import type { } from "../calibration/types"; import type { CaseInput, - CaseListFilters, - CaseMetadataPatch, OptimizationCase, OptimizationCaseStatus, OptimizationCaseType, diff --git a/tests/e2e/sample-flow.spec.ts b/tests/e2e/sample-flow.spec.ts index fa4a098..b8cb057 100644 --- a/tests/e2e/sample-flow.spec.ts +++ b/tests/e2e/sample-flow.spec.ts @@ -19,7 +19,7 @@ const reportDir = process.env.GEO_SAMPLE_REPORT_DIR ?? join(repoRoot, "test-results", "geo-sample-flow", "manual"); const baseURL = process.env.GEO_SAMPLE_BASE_URL ?? "http://127.0.0.1:3000"; -const apiAccessKey = process.env.API_ACCESS_KEY ?? ""; +const apiAccessKey = process.env.API_ACCESS_KEY ?? "local-dev-key"; const timeoutMs = Number(process.env.GEO_SAMPLE_TIMEOUT_MS ?? "600000"); const filter = process.env.GEO_SAMPLE_FILTER; const limit = Number(process.env.GEO_SAMPLE_LIMIT ?? "0"); diff --git a/tests/e2e/sample-flow/page-flow.ts b/tests/e2e/sample-flow/page-flow.ts index af61c75..2298246 100644 --- a/tests/e2e/sample-flow/page-flow.ts +++ b/tests/e2e/sample-flow/page-flow.ts @@ -1,7 +1,12 @@ import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; -import { expect, type APIRequestContext, type Page } from "@playwright/test"; +import { + expect, + type APIRequestContext, + type Locator, + type Page, +} from "@playwright/test"; import type { ArticleSample, @@ -48,10 +53,15 @@ export async function runSamplePageFlow({ await page.goto(baseURL); await fillIfVisible(page, "访问密钥", apiAccessKey); - await fillFirstAvailable(page, ["文章内容", "粘贴文章", "正文"], sample.input.body); + const bodyField = await fillFirstAvailable( + page, + ["文章内容", "粘贴文章", "正文"], + sample.input.body, + ); await fillIfVisible(page, "图片描述或图片链接", sample.input.image_lines); await page.getByLabel("目标平台").selectOption(sample.input.platform); await fillIfVisible(page, "用户要求", sample.input.user_instructions); + await ensureSubmitEnabled(page, bodyField, sample.input.body); await page.getByRole("button", { name: "开始优化" }).click(); @@ -115,13 +125,31 @@ async function fillFirstAvailable(page: Page, labels: string[], value: string) { const locator = page.getByLabel(label); if ((await locator.count()) > 0) { await locator.fill(value); - return; + return locator; } } throw new Error(`none of these labels were found: ${labels.join(", ")}`); } +async function ensureSubmitEnabled( + page: Page, + bodyField: Locator, + body: string, +) { + const submitButton = page.getByRole("button", { name: "开始优化" }); + for (let attempt = 0; attempt < 4; attempt += 1) { + await bodyField.fill(""); + await bodyField.fill(body); + if (await submitButton.isEnabled()) { + return; + } + await page.waitForTimeout(250); + } + await expect(bodyField).toHaveValue(body); + await expect(submitButton).toBeEnabled(); +} + async function fillIfVisible(page: Page, label: string, value: string) { const locator = page.getByLabel(label); if ((await locator.count()) > 0) {