iter 2
This commit is contained in:
@@ -0,0 +1,450 @@
|
||||
import { test, expect } from "#tests/e2e/fixtures/silence"
|
||||
|
||||
test.describe("Silence Settings Step (Integration)", () => {
|
||||
test.describe("Initial State", () => {
|
||||
test("should display the title and description", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { silenceStep } = silencePage
|
||||
|
||||
await expect(
|
||||
silenceStep.getByText("Параметры обнаружения тишины"),
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
silenceStep.getByText(
|
||||
"Настройте параметры для автоматического обнаружения тихих участков в видео",
|
||||
),
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test("should show all three sliders with default values", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { silenceStep } = silencePage
|
||||
|
||||
// Min silence duration slider: default 200 ms
|
||||
const durationSlider = silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Мин. длительность тишины" })
|
||||
await expect(durationSlider).toBeVisible()
|
||||
await expect(durationSlider.getByText("200 мс")).toBeVisible()
|
||||
await expect(
|
||||
durationSlider.locator("input[type='range']"),
|
||||
).toHaveValue("200")
|
||||
|
||||
// Silence threshold slider: default 16 dB
|
||||
const thresholdSlider = silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Порог тишины" })
|
||||
await expect(thresholdSlider).toBeVisible()
|
||||
await expect(thresholdSlider.getByText("16 дБ")).toBeVisible()
|
||||
await expect(
|
||||
thresholdSlider.locator("input[type='range']"),
|
||||
).toHaveValue("16")
|
||||
|
||||
// Padding slider: default 100 ms
|
||||
const paddingSlider = silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Отступ" })
|
||||
await expect(paddingSlider).toBeVisible()
|
||||
await expect(paddingSlider.getByText("100 мс")).toBeVisible()
|
||||
await expect(
|
||||
paddingSlider.locator("input[type='range']"),
|
||||
).toHaveValue("100")
|
||||
})
|
||||
|
||||
test("should display help texts for each slider", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { silenceStep } = silencePage
|
||||
|
||||
await expect(
|
||||
silenceStep.getByText(
|
||||
"Минимальная длительность тихого участка для обнаружения",
|
||||
),
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
silenceStep.getByText(
|
||||
"Уровень громкости ниже которого звук считается тишиной",
|
||||
),
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
silenceStep.getByText(
|
||||
"Дополнительный отступ по краям тихих участков",
|
||||
),
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test("should show back and forward navigation buttons", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { silenceStep } = silencePage
|
||||
|
||||
const backButton = silenceStep.getByRole("button", {
|
||||
name: "Назад",
|
||||
})
|
||||
const forwardButton = silenceStep.getByRole("button", {
|
||||
name: "Далее",
|
||||
})
|
||||
|
||||
await expect(backButton).toBeVisible()
|
||||
await expect(backButton).toBeEnabled()
|
||||
await expect(forwardButton).toBeVisible()
|
||||
await expect(forwardButton).toBeEnabled()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe("Slider Interactions", () => {
|
||||
test("should update min silence duration slider value when changed", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { silenceStep } = silencePage
|
||||
|
||||
const slider = silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Мин. длительность тишины" })
|
||||
const input = slider.locator("input[type='range']")
|
||||
|
||||
await input.fill("500")
|
||||
|
||||
await expect(input).toHaveValue("500")
|
||||
await expect(slider.getByText("500 мс")).toBeVisible()
|
||||
})
|
||||
|
||||
test("should update silence threshold slider value when changed", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { silenceStep } = silencePage
|
||||
|
||||
const slider = silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Порог тишины" })
|
||||
const input = slider.locator("input[type='range']")
|
||||
|
||||
await input.fill("24")
|
||||
|
||||
await expect(input).toHaveValue("24")
|
||||
await expect(slider.getByText("24 дБ")).toBeVisible()
|
||||
})
|
||||
|
||||
test("should update padding slider value when changed", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { silenceStep } = silencePage
|
||||
|
||||
const slider = silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Отступ" })
|
||||
const input = slider.locator("input[type='range']")
|
||||
|
||||
await input.fill("250")
|
||||
|
||||
await expect(input).toHaveValue("250")
|
||||
await expect(slider.getByText("250 мс")).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe("Successful Submission", () => {
|
||||
test("should submit with default values and navigate to Processing step", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
// Should navigate to Processing step
|
||||
await expect(
|
||||
page.locator("[data-testid='ProcessingStep']"),
|
||||
).toBeVisible({ timeout: 10_000 })
|
||||
})
|
||||
|
||||
test("should send correct request body with default values to the API", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, projectId, silenceStep } = silencePage
|
||||
|
||||
let postBody: Record<string, unknown> | null = null
|
||||
page.on("request", (req) => {
|
||||
if (
|
||||
req.url().includes("/api/tasks/silence-detect/") &&
|
||||
req.method() === "POST"
|
||||
) {
|
||||
postBody = req.postDataJSON()
|
||||
}
|
||||
})
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
await expect(
|
||||
page.locator("[data-testid='ProcessingStep']"),
|
||||
).toBeVisible({ timeout: 10_000 })
|
||||
|
||||
expect(postBody).not.toBeNull()
|
||||
expect(postBody!.project_id).toBe(projectId)
|
||||
expect(postBody!.min_silence_duration_ms).toBe(200)
|
||||
expect(postBody!.silence_threshold_db).toBe(16)
|
||||
expect(postBody!.padding_ms).toBe(100)
|
||||
// file_key should be a non-empty string populated from the uploaded file
|
||||
expect(postBody!.file_key).toBeTruthy()
|
||||
expect(typeof postBody!.file_key).toBe("string")
|
||||
})
|
||||
|
||||
test("should send correct request body with modified slider values", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
// Modify all three sliders
|
||||
await silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Мин. длительность тишины" })
|
||||
.locator("input[type='range']")
|
||||
.fill("800")
|
||||
|
||||
await silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Порог тишины" })
|
||||
.locator("input[type='range']")
|
||||
.fill("30")
|
||||
|
||||
await silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Отступ" })
|
||||
.locator("input[type='range']")
|
||||
.fill("375")
|
||||
|
||||
let postBody: Record<string, unknown> | null = null
|
||||
page.on("request", (req) => {
|
||||
if (
|
||||
req.url().includes("/api/tasks/silence-detect/") &&
|
||||
req.method() === "POST"
|
||||
) {
|
||||
postBody = req.postDataJSON()
|
||||
}
|
||||
})
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
await expect(
|
||||
page.locator("[data-testid='ProcessingStep']"),
|
||||
).toBeVisible({ timeout: 10_000 })
|
||||
|
||||
expect(postBody).not.toBeNull()
|
||||
expect(postBody!.min_silence_duration_ms).toBe(800)
|
||||
expect(postBody!.silence_threshold_db).toBe(30)
|
||||
expect(postBody!.padding_ms).toBe(375)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe("Navigation", () => {
|
||||
test("should navigate back to Verify step when back button is clicked", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Назад" })
|
||||
.click()
|
||||
|
||||
await expect(
|
||||
page.locator("[data-testid='VerifyStep']"),
|
||||
).toBeVisible({ timeout: 10_000 })
|
||||
|
||||
// Silence Settings step should no longer be visible
|
||||
await expect(silenceStep).not.toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe("Error States", () => {
|
||||
test("should stay on silence settings step when API returns network error", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
await page.route("**/api/tasks/silence-detect/**", (route) =>
|
||||
route.abort(),
|
||||
)
|
||||
await page.route("**/api/tasks/silence-detect/", (route) =>
|
||||
route.abort(),
|
||||
)
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
// Should NOT navigate to Processing step
|
||||
await expect(
|
||||
page.locator("[data-testid='ProcessingStep']"),
|
||||
).not.toBeVisible({ timeout: 5_000 })
|
||||
|
||||
// Should remain on Silence Settings step
|
||||
await expect(silenceStep).toBeVisible()
|
||||
})
|
||||
|
||||
test("should stay on silence settings step when API returns 500", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
await page.route("**/api/tasks/silence-detect/**", (route) =>
|
||||
route.fulfill({
|
||||
status: 500,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
detail: "Internal Server Error",
|
||||
}),
|
||||
}),
|
||||
)
|
||||
await page.route("**/api/tasks/silence-detect/", (route) =>
|
||||
route.fulfill({
|
||||
status: 500,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
detail: "Internal Server Error",
|
||||
}),
|
||||
}),
|
||||
)
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
// Should NOT navigate to Processing step
|
||||
await expect(
|
||||
page.locator("[data-testid='ProcessingStep']"),
|
||||
).not.toBeVisible({ timeout: 5_000 })
|
||||
|
||||
// Should remain on Silence Settings step
|
||||
await expect(silenceStep).toBeVisible()
|
||||
})
|
||||
|
||||
test("should allow retrying after a network failure", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
// First attempt: abort the request
|
||||
await page.route("**/api/tasks/silence-detect/**", (route) =>
|
||||
route.abort(),
|
||||
)
|
||||
await page.route("**/api/tasks/silence-detect/", (route) =>
|
||||
route.abort(),
|
||||
)
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
// Should stay on silence settings
|
||||
await expect(
|
||||
page.locator("[data-testid='ProcessingStep']"),
|
||||
).not.toBeVisible({ timeout: 5_000 })
|
||||
await expect(silenceStep).toBeVisible()
|
||||
|
||||
// Remove intercepts and retry
|
||||
await page.unrouteAll({ behavior: "ignoreErrors" })
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
// Should succeed and navigate to Processing step
|
||||
await expect(
|
||||
page.locator("[data-testid='ProcessingStep']"),
|
||||
).toBeVisible({ timeout: 10_000 })
|
||||
})
|
||||
|
||||
test("should show pending text and disable buttons while submission is in flight", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
// Delay the API response to observe the pending state
|
||||
await page.route(
|
||||
"**/api/tasks/silence-detect/**",
|
||||
async (route) => {
|
||||
await new Promise((r) => setTimeout(r, 3000))
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ job_id: "fake-job-id" }),
|
||||
})
|
||||
},
|
||||
)
|
||||
await page.route(
|
||||
"**/api/tasks/silence-detect/",
|
||||
async (route) => {
|
||||
await new Promise((r) => setTimeout(r, 3000))
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ job_id: "fake-job-id" }),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
await silenceStep
|
||||
.getByRole("button", { name: "Далее" })
|
||||
.click()
|
||||
|
||||
// Submit button should show "Запуск..." and be disabled
|
||||
const submitButton = silenceStep.getByRole("button", {
|
||||
name: "Запуск...",
|
||||
})
|
||||
await expect(submitButton).toBeVisible({ timeout: 2_000 })
|
||||
await expect(submitButton).toBeDisabled()
|
||||
|
||||
// Back button should also be disabled during pending state
|
||||
const backButton = silenceStep.getByRole("button", {
|
||||
name: "Назад",
|
||||
})
|
||||
await expect(backButton).toBeDisabled()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe("State Persistence", () => {
|
||||
test("should persist modified silence settings across page reloads", async ({
|
||||
silencePage,
|
||||
}) => {
|
||||
const { page, silenceStep } = silencePage
|
||||
|
||||
// Change the min silence duration slider
|
||||
const durationSlider = silenceStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Мин. длительность тишины" })
|
||||
await durationSlider.locator("input[type='range']").fill("750")
|
||||
|
||||
// Verify the value changed
|
||||
await expect(durationSlider.getByText("750 мс")).toBeVisible()
|
||||
|
||||
// Wait for the debounced save to persist (1000ms debounce + network)
|
||||
await page.waitForTimeout(2500)
|
||||
|
||||
// Reload the page
|
||||
await page.reload()
|
||||
await page.locator("[data-testid='ProjectWizard']").waitFor()
|
||||
|
||||
// Should restore to the silence settings step with persisted value
|
||||
const restoredStep = page.locator(
|
||||
"[data-testid='SilenceSettingsStep']",
|
||||
)
|
||||
await expect(restoredStep).toBeVisible({ timeout: 10_000 })
|
||||
|
||||
const restoredSlider = restoredStep
|
||||
.locator("[data-testid='Slider']")
|
||||
.filter({ hasText: "Мин. длительность тишины" })
|
||||
await expect(restoredSlider.getByText("750 мс")).toBeVisible({
|
||||
timeout: 5_000,
|
||||
})
|
||||
await expect(
|
||||
restoredSlider.locator("input[type='range']"),
|
||||
).toHaveValue("750")
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user