From 51ad06513bda181a6db9d4641ddf8086b8e766fc Mon Sep 17 00:00:00 2001 From: zhongwei9 Date: Thu, 19 Mar 2026 15:28:45 +0800 Subject: [PATCH 1/3] fix(tests): fix code-flow E2E test onboarding page handling and repository selection - Fix onboarding page detection by properly waiting for and clicking the onboarding options - Update repository selection to use correct data-testid format (slashes replaced with dashes) - Change repository from wecode-ai/Wegent to weibo_rd/common/wecode/wegent which exists in the test environment - Add better error handling and logging for team, repository, and branch selection - Add verification that repository is actually selected before continuing - Increase wait timeouts for more reliable test execution Co-Authored-By: Claude Opus 4.6 --- tests/specs/code-flow.spec.ts | 158 +++++++++++++++++++++++++++------- 1 file changed, 128 insertions(+), 30 deletions(-) diff --git a/tests/specs/code-flow.spec.ts b/tests/specs/code-flow.spec.ts index cf1eeef81..2e188b1da 100644 --- a/tests/specs/code-flow.spec.ts +++ b/tests/specs/code-flow.spec.ts @@ -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,6 +50,44 @@ 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) { + // Click on the heading's parent container (the card) + await cloudIdeHeading.click() + console.log('✓ Clicked: 使用WeCode云IDE') + } else { + // Fallback: try the first option (在IDE中使用WeCode) + const firstOption = page.locator('h3', { hasText: '在IDE中使用WeCode' }).first() + if (await firstOption.isVisible({ timeout: 2000 }).catch(() => false)) { + await firstOption.click() + console.log('✓ Clicked: 在IDE中使用WeCode') + } + } + + // 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() @@ -54,56 +95,93 @@ async function setupCodePage(page: any) { // 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() + 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')) { + await repoOptions.nth(i).click() + console.log('Selected repository by text match') + break + } + } } } - await page.waitForTimeout(500) + await page.waitForTimeout(1000) // Verify repository is selected by checking the selector text const repoSelectorText = await repoSelector.textContent() @@ -113,32 +191,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() From 712e2303afd0147ce38da36ef010be6de5975afe Mon Sep 17 00:00:00 2001 From: zhongwei9 Date: Thu, 19 Mar 2026 15:34:49 +0800 Subject: [PATCH 2/3] fix(tests): use data-testid for onboarding page click The onboarding page click was targeting the h3 heading element, but the actual clickable element is the parent card with data-testid. Changed to use data-testid="onboarding-cloud-ide-option" for the Cloud IDE option and data-testid="onboarding-ide-option" for the fallback IDE option. This follows the E2E testing guidelines to prefer data-testid selectors over text content selectors. Co-Authored-By: Claude Opus 4.6 --- tests/specs/code-flow.spec.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/specs/code-flow.spec.ts b/tests/specs/code-flow.spec.ts index 2e188b1da..d6fe5c307 100644 --- a/tests/specs/code-flow.spec.ts +++ b/tests/specs/code-flow.spec.ts @@ -68,12 +68,22 @@ async function setupCodePage(page: any) { const isCloudIdeVisible = await cloudIdeHeading.isVisible({ timeout: 3000 }).catch(() => false) if (isCloudIdeVisible) { - // Click on the heading's parent container (the card) - await cloudIdeHeading.click() - console.log('✓ Clicked: 使用WeCode云IDE') + // Click on the card using data-testid instead of the heading + // The card has the onClick handler, not the heading + const cloudIdeCard = page.locator('[data-testid="onboarding-cloud-ide-option"]').first() + const isCardVisible = await cloudIdeCard.isVisible({ timeout: 3000 }).catch(() => false) + + if (isCardVisible) { + await cloudIdeCard.click() + console.log('✓ Clicked: 使用WeCode云IDE (card)') + } else { + // Fallback: try clicking the heading's parent element + await cloudIdeHeading.locator('..').click() + console.log('✓ Clicked: 使用WeCode云IDE (parent)') + } } else { // Fallback: try the first option (在IDE中使用WeCode) - const firstOption = page.locator('h3', { hasText: '在IDE中使用WeCode' }).first() + const firstOption = page.locator('[data-testid="onboarding-ide-option"]').first() if (await firstOption.isVisible({ timeout: 2000 }).catch(() => false)) { await firstOption.click() console.log('✓ Clicked: 在IDE中使用WeCode') From b428e81659badaf245a539683fa073d779f6529b Mon Sep 17 00:00:00 2001 From: zhongwei9 Date: Thu, 19 Mar 2026 15:42:46 +0800 Subject: [PATCH 3/3] fix(tests): improve code-flow E2E test onboarding page handling The test was failing because the \"Bug or feature?\" onboarding page was not being properly detected and handled. This commit adds: 1. Multiple click strategies for the onboarding options: - Try clicking the heading element directly - Try clicking parent button element via XPath - Try clicking card div with border/cursor-pointer classes - Fallback to getByText selector 2. Better error handling with try-catch blocks 3. Improved logging to diagnose which strategy worked This ensures the test can proceed past the onboarding page regardless of the exact DOM structure. Co-Authored-By: Claude Opus 4.6 --- tests/specs/code-flow.spec.ts | 69 +++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/tests/specs/code-flow.spec.ts b/tests/specs/code-flow.spec.ts index d6fe5c307..baff84095 100644 --- a/tests/specs/code-flow.spec.ts +++ b/tests/specs/code-flow.spec.ts @@ -68,25 +68,64 @@ async function setupCodePage(page: any) { const isCloudIdeVisible = await cloudIdeHeading.isVisible({ timeout: 3000 }).catch(() => false) if (isCloudIdeVisible) { - // Click on the card using data-testid instead of the heading - // The card has the onClick handler, not the heading - const cloudIdeCard = page.locator('[data-testid="onboarding-cloud-ide-option"]').first() - const isCardVisible = await cloudIdeCard.isVisible({ timeout: 3000 }).catch(() => false) - - if (isCardVisible) { - await cloudIdeCard.click() - console.log('✓ Clicked: 使用WeCode云IDE (card)') - } else { - // Fallback: try clicking the heading's parent element - await cloudIdeHeading.locator('..').click() - console.log('✓ Clicked: 使用WeCode云IDE (parent)') + // 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 { + // 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) - const firstOption = page.locator('[data-testid="onboarding-ide-option"]').first() - if (await firstOption.isVisible({ timeout: 2000 }).catch(() => false)) { - await firstOption.click() + try { + await page.getByText('在IDE中使用WeCode').first().click({ timeout: 2000 }) console.log('✓ Clicked: 在IDE中使用WeCode') + } catch { + console.log('✗ Could not click any onboarding option') } }