-
Notifications
You must be signed in to change notification settings - Fork 93
Fix/code flow e2e test #793
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,10 +13,13 @@ async function setupCodePage(page: any) { | |
| await page.goto('/code') | ||
|
|
||
| // Set localStorage to mark onboarding as completed | ||
| // Also mark code feature onboarding as completed to skip the "Bug or feature?" page | ||
| await page.evaluate(() => { | ||
| localStorage.setItem('user_onboarding_completed', 'true') | ||
| localStorage.setItem('onboarding_in_progress', '') | ||
| localStorage.removeItem('onboarding_in_progress') | ||
| localStorage.setItem('code_onboarding_completed', 'true') | ||
| localStorage.setItem('code_feature_selected', 'cloud') | ||
| }) | ||
|
|
||
| // Reload page - now onboarding should be skipped | ||
|
|
@@ -47,63 +50,187 @@ async function setupCodePage(page: any) { | |
| // Wait for page to stabilize | ||
| await page.waitForTimeout(1000) | ||
|
|
||
| // Handle "Bug or feature?" onboarding page if present | ||
| // This page appears for first-time code feature users | ||
| // Wait a bit longer for the page to fully render | ||
| await page.waitForTimeout(2000) | ||
|
|
||
| // Check for the onboarding page by looking for the characteristic heading | ||
| const onboardingHeading = page.locator('h2', { hasText: '选择最适合您的方式继续编码之旅' }).first() | ||
| const isOnboardingVisible = await onboardingHeading.isVisible({ timeout: 5000 }).catch(() => false) | ||
|
|
||
| if (isOnboardingVisible) { | ||
| console.log('✓ Code feature onboarding page detected, selecting cloud IDE option...') | ||
|
|
||
| // Click the "使用WeCode云IDE" (Use WeCode Cloud IDE) option | ||
| // Find by the h3 heading and click on its parent card | ||
| const cloudIdeHeading = page.locator('h3', { hasText: '使用WeCode云IDE' }).first() | ||
| const isCloudIdeVisible = await cloudIdeHeading.isVisible({ timeout: 3000 }).catch(() => false) | ||
|
|
||
| if (isCloudIdeVisible) { | ||
| // Strategy: Find the clickable parent element of the h3 heading | ||
| // Try multiple approaches to find the actual clickable card | ||
| let clicked = false | ||
|
|
||
| // Strategy 1: Try clicking the heading itself (it might have click handler) | ||
| try { | ||
| await cloudIdeHeading.click({ timeout: 2000 }) | ||
| console.log('✓ Clicked: 使用WeCode云IDE (heading)') | ||
| clicked = true | ||
| } catch { | ||
|
Comment on lines
+73
to
+80
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fail fast if the onboarding dialog is still open. Right now this branch sleeps for 3 seconds and logs completion even when every click attempt falls through. Throw when no option was clicked and explicitly wait for the onboarding UI to disappear; otherwise the next clicks can still be intercepted by the modal. ✅ Suggested change if (isOnboardingVisible) {
console.log('✓ Code feature onboarding page detected, selecting cloud IDE option...')
+ let clicked = false
// Click the "使用WeCode云IDE" (Use WeCode Cloud IDE) option
// Find by the h3 heading and click on its parent card
const cloudIdeHeading = page.locator('h3', { hasText: '使用WeCode云IDE' }).first()
const isCloudIdeVisible = await cloudIdeHeading.isVisible({ timeout: 3000 }).catch(() => false)
if (isCloudIdeVisible) {
// Strategy: Find the clickable parent element of the h3 heading
// Try multiple approaches to find the actual clickable card
- let clicked = false
-
// Strategy 1: Try clicking the heading itself (it might have click handler)
try {
await cloudIdeHeading.click({ timeout: 2000 })
console.log('✓ Clicked: 使用WeCode云IDE (heading)')
clicked = true
@@
} else {
// Fallback: try the first option (在IDE中使用WeCode)
try {
await page.getByText('在IDE中使用WeCode').first().click({ timeout: 2000 })
console.log('✓ Clicked: 在IDE中使用WeCode')
+ clicked = true
} catch {
console.log('✗ Could not click any onboarding option')
}
}
- // Wait for the onboarding page to disappear
- await page.waitForTimeout(3000)
+ if (!clicked) {
+ throw new Error('Could not dismiss the code-feature onboarding')
+ }
+ await expect(onboardingHeading).toBeHidden({ timeout: 10000 })
console.log('✓ Onboarding completed, continuing with test...')
}Also applies to: 123-135 🤖 Prompt for AI Agents |
||
| // Continue to next strategy | ||
| } | ||
|
|
||
| // Strategy 2: Use XPath to find parent button | ||
| if (!clicked) { | ||
| try { | ||
| const parentButton = page.locator('h3:has-text("使用WeCode云IDE") >> xpath=ancestor::button[1]') | ||
| if (await parentButton.isVisible({ timeout: 2000 })) { | ||
| await parentButton.click() | ||
| console.log('✓ Clicked: 使用WeCode云IDE (parent button)') | ||
| clicked = true | ||
| } | ||
| } catch { | ||
| // Continue to next strategy | ||
| } | ||
| } | ||
|
|
||
| // Strategy 3: Use XPath to find nearest div with border/card styling | ||
| if (!clicked) { | ||
| try { | ||
| const cardDiv = page.locator('h3:has-text("使用WeCode云IDE") >> xpath=ancestor::div[contains(@class, "border") or contains(@class, "cursor-pointer")][1]') | ||
| if (await cardDiv.isVisible({ timeout: 2000 })) { | ||
| await cardDiv.click() | ||
| console.log('✓ Clicked: 使用WeCode云IDE (card div)') | ||
| clicked = true | ||
| } | ||
| } catch { | ||
| // Continue to next strategy | ||
| } | ||
| } | ||
|
|
||
| // Strategy 4: Click any element with the text | ||
| if (!clicked) { | ||
| try { | ||
| await page.getByText('使用WeCode云IDE').first().click({ timeout: 2000 }) | ||
| console.log('✓ Clicked: 使用WeCode云IDE (getByText)') | ||
| clicked = true | ||
| } catch { | ||
| console.log('✗ Failed to click Cloud IDE option') | ||
| } | ||
| } | ||
| } else { | ||
| // Fallback: try the first option (在IDE中使用WeCode) | ||
| try { | ||
| await page.getByText('在IDE中使用WeCode').first().click({ timeout: 2000 }) | ||
| console.log('✓ Clicked: 在IDE中使用WeCode') | ||
| } catch { | ||
| console.log('✗ Could not click any onboarding option') | ||
| } | ||
| } | ||
|
|
||
| // Wait for the onboarding page to disappear | ||
| await page.waitForTimeout(3000) | ||
|
|
||
| console.log('✓ Onboarding completed, continuing with test...') | ||
| } else { | ||
| console.log('✓ No onboarding page detected, continuing...') | ||
| } | ||
|
|
||
| // Step 1: Select dev-team agent | ||
| console.log('Selecting dev-team agent...') | ||
| const teamSelector = page.locator('[data-testid="team-selector"]').first() | ||
| await expect(teamSelector).toBeVisible({ timeout: 10000 }) | ||
|
|
||
| // Click to open team selector dropdown | ||
| await teamSelector.click() | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
|
|
||
| // Search for dev-team | ||
| const searchInput = page.locator('input[placeholder*="搜索"], input[placeholder*="Search"]').first() | ||
| if (await searchInput.isVisible({ timeout: 3000 }).catch(() => false)) { | ||
| await searchInput.fill('dev-team') | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
| console.log('Filled team search input') | ||
| } | ||
|
|
||
| // Select dev-team from dropdown | ||
| // Select dev-team from dropdown - wait for it to appear | ||
| const devTeamOption = page.locator('[data-testid="team-option-dev-team"]').first() | ||
| if (await devTeamOption.isVisible({ timeout: 3000 }).catch(() => false)) { | ||
| try { | ||
| await expect(devTeamOption).toBeVisible({ timeout: 5000 }) | ||
| await devTeamOption.click() | ||
| } else { | ||
| console.log('Selected dev-team agent') | ||
| } catch { | ||
| // Try to find by text content | ||
| const teamOptions = page.locator('[data-testid^="team-option-"]').filter({ hasText: /dev-team/i }) | ||
| if (await teamOptions.count() > 0) { | ||
| await teamOptions.first().click() | ||
| console.log('Could not find exact team option, trying fallback...') | ||
| const teamOptions = page.locator('[data-testid^="team-option-"]') | ||
| const count = await teamOptions.count() | ||
| console.log(`Found ${count} team options`) | ||
| if (count > 0) { | ||
| // Find first option containing dev-team | ||
| for (let i = 0; i < count; i++) { | ||
| const text = await teamOptions.nth(i).textContent() | ||
| console.log(`Team option ${i}: ${text}`) | ||
| if (text && text.toLowerCase().includes('dev-team')) { | ||
| await teamOptions.nth(i).click() | ||
| console.log('Selected dev-team by text match') | ||
| break | ||
| } | ||
| } | ||
| } | ||
| } | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
|
|
||
| // Step 2: Select repository wecode-ai/Wegent | ||
| // Step 2: Select repository weibo_rd/common/wecode/wegent | ||
| console.log('Selecting repository...') | ||
| const repoSelector = page.locator('[data-testid="repo-branch-selector"]').first() | ||
| await expect(repoSelector).toBeVisible({ timeout: 10000 }) | ||
|
|
||
| // Click to open repository selector | ||
| await repoSelector.click() | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
|
|
||
| // Wait for the repository dropdown to be visible | ||
| const repoDropdown = page.locator('[data-testid="repo-branch-selector-dropdown"]').first() | ||
| if (await repoDropdown.isVisible({ timeout: 5000 }).catch(() => false)) { | ||
| console.log('Repository dropdown opened') | ||
| } | ||
|
|
||
| // Search for repository | ||
| const repoSearchInput = page.locator('input[placeholder*="仓库"], input[placeholder*="repository"], input[placeholder*="搜索"]').first() | ||
| if (await repoSearchInput.isVisible({ timeout: 3000 }).catch(() => false)) { | ||
| await repoSearchInput.fill('wecode-ai/Wegent') | ||
| await page.waitForTimeout(500) | ||
| await repoSearchInput.fill('wegent') | ||
| await page.waitForTimeout(1000) | ||
| console.log('Filled repository search input') | ||
| } | ||
|
|
||
| // Select wecode-ai/Wegent repository | ||
| const wegentRepoOption = page.locator('[data-testid="repo-option-wecode-ai-Wegent"]').first() | ||
| if (await wegentRepoOption.isVisible({ timeout: 3000 }).catch(() => false)) { | ||
| // Select weibo_rd/common/wecode/wegent repository - wait for it to appear after search | ||
| // Note: data-testid replaces / with - | ||
| const wegentRepoOption = page.locator('[data-testid="repo-option-weibo_rd-common-wecode-wegent"]').first() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This hard-codes Useful? React with 👍 / 👎. |
||
| try { | ||
| await expect(wegentRepoOption).toBeVisible({ timeout: 5000 }) | ||
| await wegentRepoOption.click() | ||
| } else { | ||
| console.log('Selected weibo_rd/common/wecode/wegent repository') | ||
| } catch { | ||
| // Try to find by text content | ||
| const repoOptions = page.locator('[data-testid^="repo-option-"]').filter({ hasText: /wecode-ai/i }) | ||
| if (await repoOptions.count() > 0) { | ||
| await repoOptions.first().click() | ||
| console.log('Could not find exact repo option, trying fallback...') | ||
| const repoOptions = page.locator('[data-testid^="repo-option-"]') | ||
| const count = await repoOptions.count() | ||
| console.log(`Found ${count} repo options`) | ||
| if (count > 0) { | ||
| // Find first option containing wegent | ||
| for (let i = 0; i < count; i++) { | ||
| const text = await repoOptions.nth(i).textContent() | ||
| console.log(`Repo option ${i}: ${text}`) | ||
| if (text && text.includes('wegent')) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The fallback filter uses Useful? React with 👍 / 👎. |
||
| await repoOptions.nth(i).click() | ||
| console.log('Selected repository by text match') | ||
| break | ||
| } | ||
|
Comment on lines
+217
to
+229
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assert the exact repo/branch here, not just “something got selected”. The fallback picks the first option whose text contains 🧭 Suggested change- if (text && text.includes('wegent')) {
+ if (text?.trim() === 'weibo_rd/common/wecode/wegent') {
await repoOptions.nth(i).click()
console.log('Selected repository by text match')
break
}
...
- if (!repoBranchText || repoBranchText.includes('请选择') || repoBranchText.includes('选择')) {
- throw new Error('Repository was not properly selected. Selector text: ' + repoBranchText)
+ const normalizedRepoBranchText = repoBranchText?.replace(/\s+/g, ' ').trim() ?? ''
+ if (
+ !normalizedRepoBranchText.includes('weibo_rd/common/wecode/wegent') ||
+ !normalizedRepoBranchText.includes('main')
+ ) {
+ throw new Error(`Repository/branch selection mismatch: ${normalizedRepoBranchText}`)
}Also applies to: 284-287 🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| } | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
|
|
||
| // Verify repository is selected by checking the selector text | ||
| const repoSelectorText = await repoSelector.textContent() | ||
|
|
@@ -113,32 +240,52 @@ async function setupCodePage(page: any) { | |
| console.log('Selecting branch...') | ||
| // Click to open repo selector again to access branch selection | ||
| await repoSelector.click() | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
|
|
||
| // Search for main branch | ||
| const branchSearchInput = page.locator('input[placeholder*="分支"], input[placeholder*="branch"]').first() | ||
| if (await branchSearchInput.isVisible({ timeout: 3000 }).catch(() => false)) { | ||
| await branchSearchInput.fill('main') | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
| console.log('Filled branch search input') | ||
| } | ||
|
|
||
| // Select main branch | ||
| // Select main branch - wait for it to appear | ||
| const mainBranchOption = page.locator('[data-testid="branch-option-main"]').first() | ||
| if (await mainBranchOption.isVisible({ timeout: 3000 }).catch(() => false)) { | ||
| try { | ||
| await expect(mainBranchOption).toBeVisible({ timeout: 5000 }) | ||
| await mainBranchOption.click() | ||
| } else { | ||
| console.log('Selected main branch') | ||
| } catch { | ||
| // Try to find by text content | ||
| const branchOptions = page.locator('[data-testid^="branch-option-"]').filter({ hasText: /^main$/ }) | ||
| if (await branchOptions.count() > 0) { | ||
| await branchOptions.first().click() | ||
| console.log('Could not find exact branch option, trying fallback...') | ||
| const branchOptions = page.locator('[data-testid^="branch-option-"]') | ||
| const count = await branchOptions.count() | ||
| console.log(`Found ${count} branch options`) | ||
| if (count > 0) { | ||
| // Find first option that is exactly "main" | ||
| for (let i = 0; i < count; i++) { | ||
| const text = await branchOptions.nth(i).textContent() | ||
| console.log(`Branch option ${i}: ${text}`) | ||
| if (text && text.trim() === 'main') { | ||
| await branchOptions.nth(i).click() | ||
| console.log('Selected main branch by text match') | ||
| break | ||
| } | ||
| } | ||
| } | ||
| } | ||
| await page.waitForTimeout(500) | ||
| await page.waitForTimeout(1000) | ||
|
|
||
| // Verify repository and branch are selected | ||
| const repoBranchText = await repoSelector.textContent() | ||
| console.log('Repository/Branch selected:', repoBranchText) | ||
|
|
||
| // Verify that a repository is actually selected (not the placeholder) | ||
| if (!repoBranchText || repoBranchText.includes('请选择') || repoBranchText.includes('选择')) { | ||
| throw new Error('Repository was not properly selected. Selector text: ' + repoBranchText) | ||
| } | ||
|
|
||
| // Step 4: Select model 公网:GLM-5 | ||
| console.log('Selecting model...') | ||
| const modelSelector = page.locator('[data-testid="model-selector"]').first() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the onboarding test IDs here instead of localized copy/XPath.
This path still depends on Chinese headings/text and DOM ancestry, so it will miss the dialog in the English UI or after a copy/layout tweak. The onboarding cards already have stable test IDs in the PR context; use those directly and drop the XPath/text fallbacks.
🎯 Suggested change
Also applies to: 65-129
🤖 Prompt for AI Agents