Skip to content

fix: improve VS Code E2E test stability — wizard handling, settings, assertions#6

Open
lambrianmsft wants to merge 22 commits intomainfrom
lambrian/vscode_e2e_testing
Open

fix: improve VS Code E2E test stability — wizard handling, settings, assertions#6
lambrianmsft wants to merge 22 commits intomainfrom
lambrian/vscode_e2e_testing

Conversation

@lambrianmsft
Copy link
Owner

VS Code Extension E2E Test Improvements

Changes

  • writeTestSettings() function — centralized VS Code settings with per-phase control (validateDependencies, autoStartDesignTime)
  • Conversion tests use autoStartDesignTime: false to skip design-time process startup
  • QuickPick wizard handling — JS-based detection and dismissal of Azure connector wizard prompts, skips command palette detection
  • waitForDependencyValidation timeout fix — uses timeoutMs parameter instead of hardcoded 60s
  • Conversion file assertion — only checks for removed files (extension background file additions are expected)
  • this.skip()assert.fail() across all test files to prevent silent test skipping
  • Retry logic for legacy project cleanup in Phase 4.8b

Test Results (Local)

  • Phases 4.3-4.6: ✅ ALL PASS
  • Phase 4.7: ✅ PASS (16 tests)
  • Phase 4.8a,d,e: ✅ PASS

- ExTester UI tests: workspace creation, designer actions, inline JavaScript,
  stateless variables, designer view extensions, keyboard navigation, data mapper
- Workspace conversion tests: dialog dismiss, create workspace from legacy project,
  multiple designers simultaneously, right-click add workflow, subfolder prompt
- Shared helper modules: helpers.ts, designerHelpers.ts, runHelpers.ts
- GitHub Actions workflow for CI (vscode-e2e.yml)
- CLI integration tests: workspace conversion, project outside workspace
- Documentation: SKILL.md, CLAUDE.md updates, copilot-instructions
- Product fix: silentAuth support in getAuthorizationToken.ts
- createWorkspace validation improvements

ADO #31054994: Full coverage of all 15 steps (workspace requirement)
ExTester's page-objects use '.editor-instance' CSS selector which doesn't
exist in VS Code 1.102.0 (the version CI downloaded with 'max').
Pin to 1.108.0 which is known to work with ExTester 8.21.0.

This fixes all 13 Phase 4.1 workspace creation test failures on CI.
…tSettings, conversion assertions

- Add writeTestSettings() function for per-phase VS Code settings control
- Disable autoStartDesignTime for conversion tests (4.8a-4.8e)
- Add JS-based QuickPick dismissal for Azure connector wizard prompts
- Fix waitForDesignerWebviewTab to skip command palette detection
- Fix designerActions local waitForDependencyValidation timeout
- Relax conversion file assertion: only check for removed files
- Replace this.skip() with assert.fail() across all test files
- Add retry logic for legacy project cleanup in 4.8b
…fallback

- Phase 4.8b: enable validateDependencies so extension activates for dialog
- Phase 4.8c: restore full design-time settings (needs designer)
- Phase 4.8d/4.8e: restore conversion settings after 4.8c
- Manifest lookups: fall back to Stateless when Stateful unavailable
- clearAndType: scrollIntoView + JS click fallback for overlay/iframe issues
- wsDir/appDir lookups: fall back to any standard entry (not just Stateful)
- clearAndType: use VSBrowser.instance.driver (not describe-scoped var)
- executeOpenDesignerCommand: 10 retries × 5s delay (was 5 × 3s)
- ALL conversion tests: validateDependencies=true (extension must activate)
- conversiononly mode: same fix for validateDependencies
Root cause: opening a .code-workspace file restarts the extension host.
On CI, the extension re-downloads/validates dependencies (NodeJs, FuncCoreTools,
DotNetSDK) which takes 30-120s. Without waiting for this second activation
cycle, 'Open Designer' is never found because the extension hasn't finished
registering its commands.

Fix: openWorkspaceFileInSession now calls waitForDependencyValidation after
the workspace switch, polling up to 300s for the extension to re-activate.
Applied to both designerHelpers.ts (shared) and designerActions.test.ts (local).
Root cause: each phase launches VS Code with the workspace as a startup
resource, but then openDesignerForEntry re-opens the same workspace via
openWorkspaceFileInSession. This triggers an unnecessary extension host
restart + dependency re-validation (60s+ on CI each time).

Fix: check VS Code's window title before switching. If the workspace is
already open, skip the switch and go directly to opening workflow.json.
Also increase CI job timeout from 60→90 min as safety margin.
Root cause: waitForDependencyValidation(300s) in openWorkspaceFileInSession
created dangling Promises that outlived Mocha test timeouts. These Promises
continued polling the dead WebDriver session after the browser shut down,
causing 'invalid session id' errors to leak into the next phase.

Fix:
- Remove waitForDependencyValidation from openWorkspaceFileInSession entirely
- Use simple sleep(5s) for workspace settle instead of 300s blocking poll
- Increase executeOpenDesignerCommand to 20 retries × 10s = 200s
- Extension activation wait now happens at command-palette level, not at
  workspace-switch level (no dangling Promises)
ROOT CAUSE: prepareFreshSession used Windows-only PowerShell to kill
lingering VS Code processes. On Linux CI, this silently failed, leaving
the Phase 4.1 VS Code window running. When Phase 4.2+ launched a NEW
VS Code, ExTester's 'code -r wsFilePath' sent the workspace-open command
to the OLD window. The new window stayed bare (no folder), which is why
all screenshots showed empty VS Code with no extension behavior.

FIX:
- Use pkill on Linux/Mac to kill test-resources VS Code processes
- Also kill lingering chromedriver processes between phases
- Keep PowerShell for Windows compatibility
- Add step-by-step screenshots to standard workspace creation test
- Add failure screenshots in afterEach hook
- Revert excessive retry counts back to 5x3s (root cause was stale
  processes, not timing)
Root causes fixed:
1. switchToWebviewFrame: 10 retries x 3s (was 5x2s) for cold CI webview render
2. openDesignerForEntry: uses Explorer right-click instead of command palette
   - No timing dependency on command registration after workspace switch
   - Context menu available as soon as extension loads
   - Mirrors real user behavior
3. clearAndType: add VSBrowser import for JS-click fallback on rules engine
4. waitForDependencyValidation: added to before hooks of 4 test files
   (inlineJavascript, statelessVariables, designerViewExtended, keyboardNavigation)
5. getPhase2Resources: aligned fallback with test files
   (prefer standard+Stateful → standard → manifest[0])
Root cause analysis: code -r (openResources) works intermittently on CI.
Phases 4.2, 4.4, 4.6 succeed while 4.3, 4.5, 4.8c fail — alternating pattern
suggests race condition with stale IPC socket files from killed processes.

Fix:
- Clean up *.sock files in settings dir after killing processes
- Increase post-kill wait from 3s to 5s for full process exit
- Revert appDir startup resource change (would trigger conversion prompt)
- Keep wsFilePath for startup resources
Adds diagnostic logging to understand why openResources (code -r) doesn't
work on Linux CI:
- VS Code title before/after openResources
- Explorer sidebar row count and contents
- Settings dir file listing (looking for IPC sockets)
- Startup resource existence checks (file vs directory)

This is a diagnostic-only change to capture evidence for the next fix.
ROOT CAUSE (confirmed by diagnostics): ExTester's openResources uses
'code -r' CLI IPC which silently fails on Linux CI. When VS Code is
launched by ChromeDriver/Selenium, the IPC socket for the CLI isn't
set up. The code -r command runs, returns success, but does nothing.
This was proven by:
  - VS Code title staying 'Visual Studio Code' before AND after openResources
  - Explorer state: EMPTY after openResources
  - No .sock files in settings dir

FIX: Open workspaces via the command palette instead of code -r:
  - 'File: Open Workspace from File...' for .code-workspace files
  - 'File: Open Folder...' for directories
  - ExTester sets files.simpleDialog.enable=true so these show a
    simple text input instead of a native file picker
  - Type the full path and press Enter
  - Verify via title change and Explorer state
…lette

All VSBrowser.instance.openResources() calls use code -r IPC which
silently fails on Linux CI. Replace with:

1. openDesignerViaExplorer: Use Ctrl+P Quick Open to open workflow.json,
   then re-focus Explorer to reveal it in the tree.

2. openFileInEditor: Same Ctrl+P Quick Open approach.

3. openOverviewPage: Same approach.

4. Conversion tests (4.8a-4.8e): Add openFolderInSession() helper that
   uses command palette 'File: Open Folder...' to open directories.
   ExTester startup resources also use code -r which doesn't work.

5. multipleDesigners: Same Ctrl+P approach for openDesignerViaExplorerRightClick.
Two CI failures fixed:

1. openFolderInSession: 'element not interactable' because C# Dev Kit
   sign-in dialog blocks command palette input. Fix: aggressively
   dismiss all dialogs before each attempt, use Ctrl+Shift+P with
   '>' prefix for more reliable command execution.

2. switchToDesignerWebview: ExTester's WebView.switchToFrame() has ~5s
   default timeout. On CI, the webview's internal active-frame element
   takes longer to appear while the designer loads. Fix: retry
   switchToFrame up to 6 times (30s total) with 5s sleep between.
…me switching

ExTester's WebView.switchToFrame() searches for *[id='active-frame']
inside the webview iframe, but VS Code 1.108.0 on Linux CI doesn't
render that element. All 6 retry attempts time out after ~5s each.

Fix: Replace with manual Selenium frame navigation:
1. Find visible iframe.webview.ready element
2. driver.switchTo().frame(outerIframe)
3. If #active-frame exists inside, switch into it too
4. If not, try first inner iframe or use outer directly
5. Verify webview content is accessible (#root or body)
6. Retry loop with 60s total timeout

Applied to both designerHelpers.ts and designerActions.test.ts.
…ssal

Root cause: The 'Validating Runtime Dependency' notification downloads
NodeJS, Functions Runtime, and .NET SDK sequentially within a single
progress notification. Two problems:

1. dismissAllDialogs() was dismissing this notification during
   openWorkspaceFileInSession, killing in-progress downloads.
   Fix: Skip any dialog containing 'Validating Runtime Dependency'
   or 'Successfully installed'.

2. waitForDependencyValidation() only waited for the notification to
   disappear — which happens when NodeJS finishes (~2s) but before
   Functions Runtime finishes downloading (~200MB, ~60s). The test then
   tries to open the designer, but func binary doesn't exist yet so
   the design-time API can't start.
   Fix: After notification disappears, poll for func binary at
   ~/.azurelogicapps/dependencies/FuncCoreTools/func to actually exist
   on disk before returning. Log dependency folder contents on failure.
Root cause (confirmed from CI screenshots): The extension downloads
func, dotnet, and node binaries to ~/.azurelogicapps/dependencies/
but doesn't set execute permission on Linux. The Output panel shows:

  /bin/sh: 1: .../FuncCoreTools/func: Permission denied

The binary EXISTS on disk (our fs.existsSync check passes) but can't
be executed. The extension then tries to re-download (~200MB) every
session, and the designer can't open because the design-time API
(func host start) fails.

Fix: Run chmod -R +x on FuncCoreTools/, NodeJs/, and DotNetSDK/
directories in three places:
1. run-e2e.js prepareFreshSession() - between test phases
2. designerHelpers.ts waitForDependencyValidation() - before tests
3. designerActions.test.ts waitForDependencyValidation() - local copy
Root cause: The extension validates dependencies (showing 'Validating
Runtime Dependency' notifications for FuncCoreTools, NodeJS, DotNet,
etc.) when a workspace is opened. The design-time API (func host start)
won't start until ALL validations complete. Previously we only waited
4 seconds (PROJECT_RECOGNITION_WAIT) before opening the designer,
so the React app had no API to connect to and never rendered.

Fix: Add waitForExtensionValidationComplete() that:
1. Polls for 'Validating Runtime Dependency' notifications
2. Waits until no such notifications for 10s (stable period)
3. Then adds 3s buffer for design-time API to initialize
4. 120s overall timeout

Applied in 3 places:
- designerHelpers.ts openDesignerForEntry() (shared)
- designerActions.test.ts openDesignerForEntry() (local copy)
- multipleDesigners.test.ts after openWorkspaceFileInSession()

Also added webview HTML diagnostics dump when designer content
fails to load (Phase 2 timeout) for future debugging.
Root cause (confirmed from CI diagnostics): switchToDesignerWebview
Phase 1 checks for '#root, body' after failing to find #active-frame.
Since 'body' always exists in the outer webview bootstrap frame, it
falsely sets switched=true. We end up trapped in the OUTER frame
(41KB VS Code webview loader HTML with CSP meta tags and bootstrap
script) instead of the INNER frame where the React designer app lives.

Evidence from diagnostics dump:
  HTML length: 41148
  Body children: 1  (just the bootstrap script tag)
  No #root, no .msla-designer-canvas, no React content

Fix: Change '#root, body' selector to just '#root'. When no
#active-frame or inner iframes are found, this correctly does NOT
set switched=true, causing the retry loop to keep polling until
the inner content frame appears. Also added DOM diagnostics
logging every 15s while waiting.

Applied in both designerHelpers.ts and designerActions.test.ts.
The previous commit changed '#root, body' to just '#root' to avoid
a false positive. But CI diagnostics confirmed that #active-frame
does NOT exist on VS Code 1.108.0 Linux — the webview bootstrap
loads extension content directly in the outer frame (no nested
iframe is ever created). The outer frame body has only:
  childNodes: [#text, SCRIPT, #text], iframes: 0

With #root-only, Phase 1 times out at 60s on every designer test,
causing regressions in phases that previously passed:
  4.1: 54→20 passing (before each timeout)
  4.5: 2→0 passing (webview switch timeout)

Revert to '#root, body' which correctly enters the outer frame.
Phase 2/3 then handle waiting for the React app to mount.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant