first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:52:23 +03:00
commit 880f412e2c
2662 changed files with 866266 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
import { ModelLimitConfig } from './pages/model-limits.page'
export function createModelLimitData(overrides: Partial<ModelLimitConfig> = {}): ModelLimitConfig {
return {
provider: 'openai',
modelName: 'gpt-4o-mini',
budget: { maxLimit: 10, resetDuration: '1M' },
rateLimit: { tokenMaxLimit: 1000, requestMaxLimit: 50 },
...overrides,
}
}

View File

@@ -0,0 +1,81 @@
import { expect, test } from '../../core/fixtures/base.fixture'
import { createModelLimitData } from './model-limits.data'
const createdLimits: { modelName: string; provider: string }[] = []
test.describe('Model Limits', () => {
test.beforeEach(async ({ modelLimitsPage }) => {
await modelLimitsPage.goto()
})
test.afterEach(async ({ modelLimitsPage }) => {
await modelLimitsPage.closeSheet()
for (const { modelName, provider } of [...createdLimits]) {
try {
const exists = await modelLimitsPage.modelLimitExists(modelName, provider)
if (exists) {
await modelLimitsPage.deleteModelLimit(modelName, provider)
}
} catch (e) {
console.error(`[CLEANUP] Failed to delete model limit ${modelName}:`, e)
}
}
createdLimits.length = 0
})
test('should display create button or empty state', async ({ modelLimitsPage }) => {
const createVisible = await modelLimitsPage.createBtn.isVisible().catch(() => false)
expect(createVisible).toBe(true)
})
test('should create a model limit with budget and rate limit', async ({ modelLimitsPage }) => {
const limitData = createModelLimitData({
provider: 'openai',
budget: { maxLimit: 5, resetDuration: '1M' },
rateLimit: { tokenMaxLimit: 500, requestMaxLimit: 20 },
})
const modelName = await modelLimitsPage.createModelLimit(limitData)
createdLimits.push({ modelName, provider: limitData.provider })
const exists = await modelLimitsPage.modelLimitExists(modelName, limitData.provider)
expect(exists).toBe(true)
})
test('should edit a model limit budget and rate limit', async ({ modelLimitsPage }) => {
const limitData = createModelLimitData({ provider: 'openai' })
const modelName = await modelLimitsPage.createModelLimit(limitData)
createdLimits.push({ modelName, provider: limitData.provider })
await modelLimitsPage.editModelLimit(modelName, limitData.provider, {
budget: { maxLimit: 20 },
rateLimit: { tokenMaxLimit: 2000, requestMaxLimit: 100 },
})
const exists = await modelLimitsPage.modelLimitExists(modelName, limitData.provider)
expect(exists).toBe(true)
})
test('should delete a model limit', async ({ modelLimitsPage }) => {
const limitData = createModelLimitData({
provider: 'openai',
budget: { maxLimit: 5 },
})
const modelName = await modelLimitsPage.createModelLimit(limitData)
createdLimits.push({ modelName, provider: limitData.provider })
let exists = await modelLimitsPage.modelLimitExists(modelName, limitData.provider)
expect(exists).toBe(true)
await modelLimitsPage.deleteModelLimit(modelName, limitData.provider)
const idx = createdLimits.findIndex(
(limit) => limit.modelName === modelName && limit.provider === limitData.provider
)
if (idx >= 0) createdLimits.splice(idx, 1)
exists = await modelLimitsPage.modelLimitExists(modelName, limitData.provider)
expect(exists).toBe(false)
})
})

View File

@@ -0,0 +1,138 @@
import type { Locator, Page } from '@playwright/test'
import { expect } from '../../../core/fixtures/base.fixture'
import { BasePage } from '../../../core/pages/base.page'
import { fillSelect, waitForNetworkIdle } from '../../../core/utils/test-helpers'
export interface ModelLimitConfig {
provider: string
modelName: string
budget?: { maxLimit: number; resetDuration?: string }
rateLimit?: {
tokenMaxLimit?: number
requestMaxLimit?: number
}
}
function toTestIdPart(value: string): string {
return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')
}
export class ModelLimitsPage extends BasePage {
readonly createBtn: Locator
readonly table: Locator
readonly sheet: Locator
constructor(page: Page) {
super(page)
this.createBtn = page.getByTestId('model-limits-button-create')
this.table = page.getByTestId('model-limits-table')
this.sheet = page.getByTestId('model-limit-sheet')
}
async goto(): Promise<void> {
await this.page.goto('/workspace/model-limits')
await waitForNetworkIdle(this.page)
}
getModelLimitRow(modelName: string, provider: string = 'all'): Locator {
return this.page.getByTestId(`model-limit-row-${toTestIdPart(modelName)}-${toTestIdPart(provider)}`)
}
async modelLimitExists(modelName: string, provider: string = 'all'): Promise<boolean> {
const row = this.getModelLimitRow(modelName, provider)
return (await row.count()) > 0
}
/**
* Create a model limit via the sheet: selects provider, selects the requested
* model (config.modelName) in the search dropdown, fills budget and rate
* limit, then saves. Returns the selected model name for use in exists/edit/delete.
*/
async createModelLimit(config: ModelLimitConfig): Promise<string> {
await this.createBtn.click()
await expect(this.sheet).toBeVisible({ timeout: 5000 })
await this.waitForSheetAnimation()
// Select provider (stable testid; sheet is the only one open)
await fillSelect(
this.page,
'[data-testid="model-limit-provider-select"]',
config.provider === 'all' ? 'All Providers' : config.provider
)
// Model multiselect - search and select requested model deterministically
const modelSelectContainer = this.sheet.getByTestId('model-limit-model-select')
const modelInput = modelSelectContainer.locator('input')
await modelInput.fill(config.modelName)
await this.page.waitForSelector('[role="option"]', { timeout: 10000 })
const targetOption = this.page.getByRole('option', { name: config.modelName, exact: true })
await expect(targetOption).toBeVisible({ timeout: 10000 })
await targetOption.click()
const selectedModelName = config.modelName
if (config.budget?.maxLimit !== undefined) {
const budgetInput = this.page.locator('#modelBudgetMaxLimit')
await budgetInput.fill(String(config.budget.maxLimit))
}
if (config.rateLimit?.tokenMaxLimit !== undefined) {
await this.page.locator('#modelTokenMaxLimit').fill(String(config.rateLimit.tokenMaxLimit))
}
if (config.rateLimit?.requestMaxLimit !== undefined) {
await this.page.locator('#modelRequestMaxLimit').fill(String(config.rateLimit.requestMaxLimit))
}
const saveBtn = this.page.getByRole('button', { name: /Create Limit/i })
await saveBtn.click()
await this.waitForSuccessToast()
await expect(this.sheet).not.toBeVisible({ timeout: 10000 })
return selectedModelName
}
async editModelLimit(modelName: string, provider: string, updates: Partial<ModelLimitConfig>): Promise<void> {
const editBtn = this.page.getByTestId(`model-limit-button-edit-${toTestIdPart(modelName)}-${toTestIdPart(provider)}`)
await editBtn.click()
await expect(this.sheet).toBeVisible({ timeout: 5000 })
await this.waitForSheetAnimation()
if (updates.budget?.maxLimit !== undefined) {
const budgetInput = this.page.locator('#modelBudgetMaxLimit')
await budgetInput.clear()
await budgetInput.fill(String(updates.budget.maxLimit))
}
if (updates.rateLimit?.tokenMaxLimit !== undefined) {
const tokenInput = this.page.locator('#modelTokenMaxLimit')
await tokenInput.clear()
await tokenInput.fill(String(updates.rateLimit.tokenMaxLimit))
}
if (updates.rateLimit?.requestMaxLimit !== undefined) {
const requestInput = this.page.locator('#modelRequestMaxLimit')
await requestInput.clear()
await requestInput.fill(String(updates.rateLimit.requestMaxLimit))
}
const saveBtn = this.page.getByRole('button', { name: /Save Changes|Create Limit/i })
await saveBtn.click()
await this.waitForSuccessToast()
await expect(this.sheet).not.toBeVisible({ timeout: 10000 })
}
async deleteModelLimit(modelName: string, provider: string = 'all'): Promise<void> {
const deleteBtn = this.page.getByTestId(`model-limit-button-delete-${toTestIdPart(modelName)}-${toTestIdPart(provider)}`)
await deleteBtn.click()
const confirmDialog = this.page.locator('[role="alertdialog"]')
await confirmDialog.getByRole('button', { name: /Delete/i }).click()
await this.waitForSuccessToast()
await this.page.waitForTimeout(1000)
}
async closeSheet(): Promise<void> {
if (await this.sheet.isVisible().catch(() => false)) {
await this.page.keyboard.press('Escape')
await expect(this.sheet).not.toBeVisible({ timeout: 5000 }).catch(() => {})
}
}
}