axonhub / frontend /tests /users-projects.spec.ts
llzai's picture
Upload 1793 files
9853396 verified
import { test, expect } from '@playwright/test'
import { gotoAndEnsureAuth, waitForGraphQLOperation } from './auth.utils'
test.describe('Users - Add to Project', () => {
let testProjectId: string
let testProjectName: string
let testUserEmail: string
test.beforeAll(async ({ browser }) => {
test.setTimeout(120000)
// Create a test project and user for the tests
const context = await browser.newContext()
const page = await context.newPage()
await gotoAndEnsureAuth(page, '/projects')
// Create a test project
const uniqueSuffix = Date.now().toString().slice(-6)
testProjectName = `pw-test-Project for Users ${uniqueSuffix}`
const createProjectButton = page.getByRole('button', { name: /创建项目|Create Project|新建项目|Add Project/i })
await createProjectButton.click()
const projectDialog = page.getByRole('dialog')
await projectDialog.getByLabel(/名称|Name/i).fill(testProjectName)
await projectDialog.getByLabel(/描述|Description/i).fill('pw-test project for user assignment tests')
await Promise.all([
waitForGraphQLOperation(page, 'CreateProject'),
projectDialog.getByRole('button', { name: /创建|Create|保存|Save/i }).click()
])
await page.waitForTimeout(500)
// Create a test user
await page.goto('/users')
await page.waitForLoadState('domcontentloaded')
testUserEmail = `pw-test-project-user-${uniqueSuffix}@example.com`
const createUserButton = page.getByRole('button', { name: /添加用户|Add User|新增用户|Create User/i })
await createUserButton.click()
const userDialog = page.getByRole('dialog')
await userDialog.getByLabel(/邮箱|Email/i).fill(testUserEmail)
await userDialog.getByLabel(/名|First Name/i).fill('pw-test-ProjectTest')
await userDialog.getByLabel(/姓|Last Name/i).fill(uniqueSuffix)
const passwordField = userDialog.locator('input[type="password"]').first()
await passwordField.fill('TestPass123!')
const confirmPasswordField = userDialog.locator('input[type="password"]').last()
await confirmPasswordField.fill('TestPass123!')
await Promise.all([
waitForGraphQLOperation(page, 'CreateUser'),
userDialog.getByRole('button', { name: /保存|Save|创建|Create|Save changes/i }).click()
])
await page.waitForTimeout(500)
await context.close()
})
test.beforeEach(async ({ page }) => {
test.setTimeout(60000)
await gotoAndEnsureAuth(page, '/users')
})
test('can add user to project with owner permission', async ({ page }) => {
// Find the test user in the table
const usersTable = page.locator('[data-testid="users-table"], table:has(th), table').first()
const userRow = usersTable.locator('tbody tr').filter({ hasText: testUserEmail })
await expect(userRow).toBeVisible()
// Open the actions menu
const actionsTrigger = userRow.locator('[data-testid="row-actions"], button:has(svg), .dropdown-trigger, .action-button, button:has-text("Open menu")').first()
await actionsTrigger.click()
// Click "Add to Project" menu item
const menu = page.getByRole('menu')
await expect(menu).toBeVisible()
await menu.getByRole('menuitem', { name: /添加到项目|Add to Project|加入项目/i }).focus()
await page.keyboard.press('Enter')
// Verify the Add to Project dialog opens
const addToProjectDialog = page.getByRole('dialog')
await expect(addToProjectDialog).toBeVisible()
await expect(addToProjectDialog).toContainText(/添加到项目|Add to Project/i)
// Select the test project
const projectSelect = addToProjectDialog.locator('button[role="combobox"], select, .select-trigger').first()
await projectSelect.click()
// Wait for the dropdown to appear and select the project
const projectOption = page.locator('[role="option"], [role="menuitem"]').filter({ hasText: testProjectName })
await expect(projectOption).toBeVisible()
await projectOption.click()
// Check the "Owner" checkbox
const ownerCheckbox = addToProjectDialog.getByRole('checkbox', { name: /所有者|Owner|拥有者/i })
await expect(ownerCheckbox).toBeVisible()
await ownerCheckbox.check()
// Submit the form
await Promise.all([
waitForGraphQLOperation(page, 'AddUserToProject'),
addToProjectDialog.getByRole('button', { name: /添加|Add|保存|Save|确认|Confirm/i }).click()
])
// Verify success (dialog should close)
await expect(addToProjectDialog).not.toBeVisible()
})
test('can add user to project with specific roles', async ({ page }) => {
// Create another test user for this test
const uniqueSuffix = Date.now().toString().slice(-6)
const newUserEmail = `pw-test-roles-user-${uniqueSuffix}@example.com`
const createUserButton = page.getByRole('button', { name: /添加用户|Add User|新增用户|Create User/i })
await createUserButton.click()
const userDialog = page.getByRole('dialog')
await userDialog.getByLabel(/邮箱|Email/i).fill(newUserEmail)
await userDialog.getByLabel(/名|First Name/i).fill('pw-test-RolesTest')
await userDialog.getByLabel(/姓|Last Name/i).fill(uniqueSuffix)
const passwordField = userDialog.locator('input[type="password"]').first()
await passwordField.fill('TestPass123!')
const confirmPasswordField = userDialog.locator('input[type="password"]').last()
await confirmPasswordField.fill('TestPass123!')
await Promise.all([
waitForGraphQLOperation(page, 'CreateUser'),
userDialog.getByRole('button', { name: /保存|Save|创建|Create|Save changes/i }).click()
])
await page.waitForTimeout(500)
// Find the new user in the table
const usersTable = page.locator('[data-testid="users-table"], table:has(th), table').first()
const userRow = usersTable.locator('tbody tr').filter({ hasText: newUserEmail })
await expect(userRow).toBeVisible()
// Open the actions menu
const actionsTrigger = userRow.locator('[data-testid="row-actions"], button:has(svg), .dropdown-trigger, .action-button, button:has-text("Open menu")').first()
await actionsTrigger.click()
// Click "Add to Project" menu item
const menu = page.getByRole('menu')
await expect(menu).toBeVisible()
await menu.getByRole('menuitem', { name: /添加到项目|Add to Project|加入项目/i }).focus()
await page.keyboard.press('Enter')
// Verify the Add to Project dialog opens
const addToProjectDialog = page.getByRole('dialog')
await expect(addToProjectDialog).toBeVisible()
// Select the test project
const projectSelect = addToProjectDialog.locator('button[role="combobox"], select, .select-trigger').first()
await projectSelect.click()
const projectOption = page.locator('[role="option"], [role="menuitem"]').filter({ hasText: testProjectName })
await expect(projectOption).toBeVisible()
await projectOption.click()
// Wait for roles to load
await page.waitForTimeout(1000)
// Check if there are any roles available
const rolesSection = addToProjectDialog.locator('text=/项目角色|Project Roles/i')
if (await rolesSection.isVisible()) {
// Try to select a role if available
const firstRoleCheckbox = addToProjectDialog.locator('input[type="checkbox"][id^="role-"]').first()
if (await firstRoleCheckbox.isVisible()) {
await firstRoleCheckbox.check()
}
}
// Submit the form
await Promise.all([
waitForGraphQLOperation(page, 'AddUserToProject'),
addToProjectDialog.getByRole('button', { name: /添加|Add|保存|Save|确认|Confirm/i }).click()
])
// Verify success (dialog should close)
await expect(addToProjectDialog).not.toBeVisible()
})
test('can add user to project with specific scopes', async ({ page }) => {
// Create another test user for this test
const uniqueSuffix = Date.now().toString().slice(-6)
const newUserEmail = `pw-test-scopes-user-${uniqueSuffix}@example.com`
const createUserButton = page.getByRole('button', { name: /添加用户|Add User|新增用户|Create User/i })
await createUserButton.click()
const userDialog = page.getByRole('dialog')
await userDialog.getByLabel(/邮箱|Email/i).fill(newUserEmail)
await userDialog.getByLabel(/名|First Name/i).fill('pw-test-ScopesTest')
await userDialog.getByLabel(/姓|Last Name/i).fill(uniqueSuffix)
const passwordField = userDialog.locator('input[type="password"]').first()
await passwordField.fill('TestPass123!')
const confirmPasswordField = userDialog.locator('input[type="password"]').last()
await confirmPasswordField.fill('TestPass123!')
await Promise.all([
waitForGraphQLOperation(page, 'CreateUser'),
userDialog.getByRole('button', { name: /保存|Save|创建|Create|Save changes/i }).click()
])
await page.waitForTimeout(500)
// Find the new user in the table
const usersTable = page.locator('[data-testid="users-table"], table:has(th), table').first()
const userRow = usersTable.locator('tbody tr').filter({ hasText: newUserEmail })
await expect(userRow).toBeVisible()
// Open the actions menu
const actionsTrigger = userRow.locator('[data-testid="row-actions"], button:has(svg), .dropdown-trigger, .action-button, button:has-text("Open menu")').first()
await actionsTrigger.click()
// Click "Add to Project" menu item
const menu = page.getByRole('menu')
await expect(menu).toBeVisible()
await menu.getByRole('menuitem', { name: /添加到项目|Add to Project|加入项目/i }).focus()
await page.keyboard.press('Enter')
// Verify the Add to Project dialog opens
const addToProjectDialog = page.getByRole('dialog')
await expect(addToProjectDialog).toBeVisible()
// Select the test project
const projectSelect = addToProjectDialog.locator('button[role="combobox"], select, .select-trigger').first()
await projectSelect.click()
const projectOption = page.locator('[role="option"], [role="menuitem"]').filter({ hasText: testProjectName })
await expect(projectOption).toBeVisible()
await projectOption.click()
// Wait for scopes to load
await page.waitForTimeout(1000)
// Check if there are any scopes available
const scopesSection = addToProjectDialog.locator('text=/项目权限|Project Scopes|项目范围/i')
if (await scopesSection.isVisible()) {
// Try to select a scope if available
const firstScopeCheckbox = addToProjectDialog.locator('input[type="checkbox"][id^="scope-"]').first()
if (await firstScopeCheckbox.isVisible()) {
await firstScopeCheckbox.check()
}
}
// Submit the form
await Promise.all([
waitForGraphQLOperation(page, 'AddUserToProject'),
addToProjectDialog.getByRole('button', { name: /添加|Add|保存|Save|确认|Confirm/i }).click()
])
// Verify success (dialog should close)
await expect(addToProjectDialog).not.toBeVisible()
})
test('shows disabled projects that user is already member of', async ({ page }) => {
// Find the test user that was already added to the project
const usersTable = page.locator('[data-testid="users-table"], table:has(th), table').first()
const userRow = usersTable.locator('tbody tr').filter({ hasText: testUserEmail })
await expect(userRow).toBeVisible()
// Open the actions menu
const actionsTrigger = userRow.locator('[data-testid="row-actions"], button:has(svg), .dropdown-trigger, .action-button, button:has-text("Open menu")').first()
await actionsTrigger.click()
// Click "Add to Project" menu item
const menu = page.getByRole('menu')
await expect(menu).toBeVisible()
await menu.getByRole('menuitem', { name: /添加到项目|Add to Project|加入项目/i }).focus()
await page.keyboard.press('Enter')
// Verify the Add to Project dialog opens
const addToProjectDialog = page.getByRole('dialog')
await expect(addToProjectDialog).toBeVisible()
// Open the project dropdown
const projectSelect = addToProjectDialog.locator('button[role="combobox"], select, .select-trigger').first()
await projectSelect.click()
// The test project should be in the list but disabled
// Note: This test verifies the UI shows the project as disabled
// The exact implementation may vary, so we just verify the dropdown opens
const dropdown = page.locator('[role="listbox"], [role="menu"]')
await expect(dropdown).toBeVisible()
// Close the dialog
await page.keyboard.press('Escape')
})
test('validates project selection is required', async ({ page }) => {
// Create a test user for validation test
const uniqueSuffix = Date.now().toString().slice(-6)
const newUserEmail = `playwright-validation-${uniqueSuffix}@example.com`
const createUserButton = page.getByRole('button', { name: /添加用户|Add User|新增用户|Create User/i })
await expect(createUserButton).toBeVisible({ timeout: 10000 })
await createUserButton.click()
const userDialog = page.getByRole('dialog')
await userDialog.getByLabel(/邮箱|Email/i).fill(newUserEmail)
await userDialog.getByLabel(/名|First Name/i).fill('ValidationTest')
await userDialog.getByLabel(/姓|Last Name/i).fill(uniqueSuffix)
const passwordField = userDialog.locator('input[type="password"]').first()
await passwordField.fill('TestPass123!')
const confirmPasswordField = userDialog.locator('input[type="password"]').last()
await confirmPasswordField.fill('TestPass123!')
await Promise.all([
waitForGraphQLOperation(page, 'CreateUser'),
userDialog.getByRole('button', { name: /保存|Save|创建|Create|Save changes/i }).click()
])
await page.waitForTimeout(500)
// Find the new user in the table
const usersTable = page.locator('[data-testid="users-table"], table:has(th), table').first()
const userRow = usersTable.locator('tbody tr').filter({ hasText: newUserEmail })
await expect(userRow).toBeVisible()
// Open the actions menu
const actionsTrigger = userRow.locator('[data-testid="row-actions"], button:has(svg), .dropdown-trigger, .action-button, button:has-text("Open menu")').first()
await actionsTrigger.click()
// Click "Add to Project" menu item
const menu = page.getByRole('menu')
await expect(menu).toBeVisible()
await menu.getByRole('menuitem', { name: /添加到项目|Add to Project|加入项目/i }).focus()
await page.keyboard.press('Enter')
// Verify the Add to Project dialog opens
const addToProjectDialog = page.getByRole('dialog')
await expect(addToProjectDialog).toBeVisible()
// Try to submit without selecting a project
const submitButton = addToProjectDialog.getByRole('button', { name: /添加|Add|保存|Save|确认|Confirm/i })
await submitButton.click()
// Dialog should remain open due to validation error
await expect(addToProjectDialog).toBeVisible()
})
test('can cancel adding user to project', async ({ page }) => {
// Create a test user
const uniqueSuffix = Date.now().toString().slice(-6)
const newUserEmail = `playwright-cancel-${uniqueSuffix}@example.com`
const createUserButton = page.getByRole('button', { name: /添加用户|Add User|新增用户|Create User/i })
await createUserButton.click()
const userDialog = page.getByRole('dialog')
await userDialog.getByLabel(/邮箱|Email/i).fill(newUserEmail)
await userDialog.getByLabel(/名|First Name/i).fill('CancelTest')
await userDialog.getByLabel(/姓|Last Name/i).fill(uniqueSuffix)
const passwordField = userDialog.locator('input[type="password"]').first()
await passwordField.fill('TestPass123!')
const confirmPasswordField = userDialog.locator('input[type="password"]').last()
await confirmPasswordField.fill('TestPass123!')
await Promise.all([
waitForGraphQLOperation(page, 'CreateUser'),
userDialog.getByRole('button', { name: /保存|Save|创建|Create|Save changes/i }).click()
])
await page.waitForTimeout(500)
// Find the new user in the table
const usersTable = page.locator('[data-testid="users-table"], table:has(th), table').first()
const userRow = usersTable.locator('tbody tr').filter({ hasText: newUserEmail })
await expect(userRow).toBeVisible()
// Open the actions menu
const actionsTrigger = userRow.locator('[data-testid="row-actions"], button:has(svg), .dropdown-trigger, .action-button, button:has-text("Open menu")').first()
await actionsTrigger.click()
// Click "Add to Project" menu item
const menu = page.getByRole('menu')
await expect(menu).toBeVisible()
await menu.getByRole('menuitem', { name: /添加到项目|Add to Project|加入项目/i }).focus()
await page.keyboard.press('Enter')
// Verify the Add to Project dialog opens
const addToProjectDialog = page.getByRole('dialog')
await expect(addToProjectDialog).toBeVisible()
// Close the dialog by pressing Escape
await page.keyboard.press('Escape')
// Dialog should be closed
await expect(addToProjectDialog).not.toBeVisible()
})
})