| @@ -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); | |||||
| }); | |||||
| }); | |||||