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 countGeneratorRatioRows(page: Page) { return await page.getByTestId(/^generator-ratio-value-/).count(); } async function fetchModelPricing( request: APIRequestContext, model: string, userId: number, ): Promise { const response = await request.get( `/api/option/model_pricing/${encodeURIComponent(model)}`, { headers: { 'New-API-User': String(userId), }, }, ); 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.getByTestId('generator-strategy-replace-all').click(); const qualityRowIndex = (await countGeneratorRatioRows(page)) - 1; await fillByTestId(page, `generator-ratio-value-${qualityRowIndex}`, '2'); await fillByTestId(page, `generator-ratio-ratio-${qualityRowIndex}`, '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 rootUserId = await page.evaluate(() => { const user = window.localStorage.getItem('user'); return user ? JSON.parse(user).id : null; }); expect(typeof rootUserId).toBe('number'); const data = await fetchModelPricing(request, model, rootUserId as number); 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); }); });