| @@ -0,0 +1,107 @@ | |||
| import type { APIRequestContext, Locator, Page } from '@playwright/test'; | |||
| import { expect, rootStorageStatePath, test } from './fixtures/cluster'; | |||
| type ModelPricingConfig = { | |||
| success: boolean; | |||
| data: { | |||
| schema_version: number; | |||
| scope: string; | |||
| dimensions: Array<{ key: string }>; | |||
| table: unknown[]; | |||
| }; | |||
| }; | |||
| const modelName = () => | |||
| `e2e-video-pricing-model-${Date.now()}-${Math.floor(Math.random() * 1000)}`; | |||
| async function fillControl(locator: Locator, value: string) { | |||
| const input = locator.locator('input'); | |||
| if ((await input.count()) > 0) { | |||
| await input.first().fill(value); | |||
| return; | |||
| } | |||
| await locator.fill(value); | |||
| } | |||
| async function fillByTestId(page: Page, testId: string, value: string) { | |||
| await fillControl(page.getByTestId(testId), value); | |||
| } | |||
| async function fetchModelPricing( | |||
| request: APIRequestContext, | |||
| model: string, | |||
| ): Promise<ModelPricingConfig> { | |||
| const response = await request.get( | |||
| `/api/option/model_pricing/${encodeURIComponent(model)}`, | |||
| ); | |||
| expect(response.ok()).toBeTruthy(); | |||
| return (await response.json()) as ModelPricingConfig; | |||
| } | |||
| test.describe.serial('Model Pricing E2E', () => { | |||
| test.use({ storageState: rootStorageStatePath }); | |||
| test('root can save and reload a generated model pricing config', async ({ | |||
| page, | |||
| request, | |||
| }) => { | |||
| const model = modelName(); | |||
| await page.goto('/console/setting?tab=ratio'); | |||
| await page.getByTestId('model-pricing-tab').click(); | |||
| await expect(page.getByTestId('model-pricing-page')).toBeVisible(); | |||
| await page.getByTestId('model-pricing-add-model').click(); | |||
| await expect(page.getByTestId('model-pricing-editor')).toBeVisible(); | |||
| await fillByTestId(page, 'model-pricing-model-name', model); | |||
| await fillByTestId(page, 'dimension-key-0', 'duration'); | |||
| await fillByTestId(page, 'dimension-source-path-0', 'duration'); | |||
| await page.getByTestId('dimension-add').click(); | |||
| await fillByTestId(page, 'dimension-key-1', 'quality'); | |||
| await fillByTestId(page, 'dimension-source-path-1', 'quality'); | |||
| await page.getByTestId('model-pricing-open-generator').click(); | |||
| await expect(page.getByTestId('model-pricing-generator')).toBeVisible(); | |||
| await fillByTestId(page, 'generator-base-price', '0.2'); | |||
| const generator = page.getByTestId('model-pricing-generator'); | |||
| await generator.locator('input[value="replace_all"]').check({ force: true }); | |||
| await fillByTestId(page, 'generator-ratio-value-2', '1'); | |||
| await fillByTestId(page, 'generator-ratio-ratio-2', '1.5'); | |||
| await expect(page.getByTestId('generator-apply')).toBeEnabled(); | |||
| await page.getByTestId('generator-apply').click(); | |||
| const saveResponsePromise = page.waitForResponse( | |||
| (response) => | |||
| response.request().method() === 'PUT' && | |||
| response | |||
| .url() | |||
| .includes(`/api/option/model_pricing/${encodeURIComponent(model)}`), | |||
| ); | |||
| await page.getByTestId('model-pricing-save').click(); | |||
| const saveResponse = await saveResponsePromise; | |||
| expect(saveResponse.ok()).toBeTruthy(); | |||
| const saveBody = await saveResponse.json(); | |||
| expect(saveBody.success).toBe(true); | |||
| await page.reload(); | |||
| await page.getByTestId('model-pricing-tab').click(); | |||
| await expect(page.getByTestId('model-pricing-page')).toBeVisible(); | |||
| await fillByTestId(page, 'model-pricing-search', model); | |||
| await expect(page.getByTestId('model-pricing-table')).toContainText(model); | |||
| await page.getByTestId(`model-pricing-edit-${model}`).click(); | |||
| await expect(page.getByTestId('model-pricing-editor')).toBeVisible(); | |||
| const data = await fetchModelPricing(request, model); | |||
| expect(data.success).toBe(true); | |||
| expect(data.data.schema_version).toBe(1); | |||
| expect(data.data.scope).toBe('model'); | |||
| expect(data.data.dimensions.map((dimension) => dimension.key)).toEqual([ | |||
| 'duration', | |||
| 'quality', | |||
| ]); | |||
| expect(data.data.table.length).toBeGreaterThan(0); | |||
| }); | |||
| }); | |||