You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

125 rivejä
4.4 KiB

  1. import type { APIRequestContext, Locator, Page } from '@playwright/test';
  2. import { expect, rootStorageStatePath, test } from './fixtures/cluster';
  3. type ModelPricingConfig = {
  4. success: boolean;
  5. data: {
  6. schema_version: number;
  7. scope: string;
  8. dimensions: Array<{ key: string }>;
  9. table: unknown[];
  10. };
  11. };
  12. const modelName = () =>
  13. `e2e-video-pricing-model-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
  14. async function fillControl(locator: Locator, value: string) {
  15. const input = locator.locator('input');
  16. if ((await input.count()) > 0) {
  17. await input.first().fill(value);
  18. return;
  19. }
  20. await locator.fill(value);
  21. }
  22. async function fillByTestId(page: Page, testId: string, value: string) {
  23. await fillControl(page.getByTestId(testId), value);
  24. }
  25. async function countGeneratorRatioRows(page: Page) {
  26. return await page.getByTestId(/^generator-ratio-value-/).count();
  27. }
  28. async function fetchModelPricing(
  29. request: APIRequestContext,
  30. model: string,
  31. userId: number,
  32. ): Promise<ModelPricingConfig> {
  33. const response = await request.get(
  34. `/api/option/model_pricing/${encodeURIComponent(model)}`,
  35. {
  36. headers: {
  37. 'New-API-User': String(userId),
  38. },
  39. },
  40. );
  41. expect(response.ok()).toBeTruthy();
  42. return (await response.json()) as ModelPricingConfig;
  43. }
  44. test.describe.serial('Model Pricing E2E', () => {
  45. test.use({ storageState: rootStorageStatePath });
  46. test('root can save and reload a generated model pricing config', async ({
  47. page,
  48. request,
  49. }) => {
  50. const model = modelName();
  51. await page.goto('/console/setting?tab=ratio');
  52. await page.getByTestId('model-pricing-tab').click();
  53. await expect(page.getByTestId('model-pricing-page')).toBeVisible();
  54. await page.getByTestId('model-pricing-add-model').click();
  55. await expect(page.getByTestId('model-pricing-editor')).toBeVisible();
  56. await fillByTestId(page, 'model-pricing-model-name', model);
  57. await fillByTestId(page, 'dimension-key-0', 'duration');
  58. await fillByTestId(page, 'dimension-source-path-0', 'duration');
  59. await page.getByTestId('dimension-add').click();
  60. await fillByTestId(page, 'dimension-key-1', 'quality');
  61. await fillByTestId(page, 'dimension-source-path-1', 'quality');
  62. await page.getByTestId('model-pricing-open-generator').click();
  63. await expect(page.getByTestId('model-pricing-generator')).toBeVisible();
  64. await fillByTestId(page, 'generator-base-price', '0.2');
  65. const generator = page.getByTestId('model-pricing-generator');
  66. await generator.getByTestId('generator-strategy-replace-all').click();
  67. const qualityRowIndex = (await countGeneratorRatioRows(page)) - 1;
  68. await fillByTestId(page, `generator-ratio-value-${qualityRowIndex}`, '2');
  69. await fillByTestId(page, `generator-ratio-ratio-${qualityRowIndex}`, '1.5');
  70. await expect(page.getByTestId('generator-apply')).toBeEnabled();
  71. await page.getByTestId('generator-apply').click();
  72. const saveResponsePromise = page.waitForResponse(
  73. (response) =>
  74. response.request().method() === 'PUT' &&
  75. response
  76. .url()
  77. .includes(`/api/option/model_pricing/${encodeURIComponent(model)}`),
  78. );
  79. await page.getByTestId('model-pricing-save').click();
  80. const saveResponse = await saveResponsePromise;
  81. expect(saveResponse.ok()).toBeTruthy();
  82. const saveBody = await saveResponse.json();
  83. expect(saveBody.success).toBe(true);
  84. await page.reload();
  85. await page.getByTestId('model-pricing-tab').click();
  86. await expect(page.getByTestId('model-pricing-page')).toBeVisible();
  87. await fillByTestId(page, 'model-pricing-search', model);
  88. await expect(page.getByTestId('model-pricing-table')).toContainText(model);
  89. await page.getByTestId(`model-pricing-edit-${model}`).click();
  90. await expect(page.getByTestId('model-pricing-editor')).toBeVisible();
  91. const rootUserId = await page.evaluate(() => {
  92. const user = window.localStorage.getItem('user');
  93. return user ? JSON.parse(user).id : null;
  94. });
  95. expect(typeof rootUserId).toBe('number');
  96. const data = await fetchModelPricing(request, model, rootUserId as number);
  97. expect(data.success).toBe(true);
  98. expect(data.data.schema_version).toBe(1);
  99. expect(data.data.scope).toBe('model');
  100. expect(data.data.dimensions.map((dimension) => dimension.key)).toEqual([
  101. 'duration',
  102. 'quality',
  103. ]);
  104. expect(data.data.table.length).toBeGreaterThan(0);
  105. });
  106. });