Skill: ExTester UI E2E Tests for VS Code Logic Apps Extension
Status: IN PROGRESS — Phase 4.1 (createWorkspace): 63 passing, 1 failing (pre-existing product bug). Phase 4.2 (designer actions): 2 passing, 0 failing — full lifecycle tests covering designer authoring → save → debug → overview → run trigger → verify succeeded. ~5 min runtime.
Last updated: 2026-03-03
1. What This Is
TRUE end-to-end tests using vscode-extension-tester (ExTester v8.21.0) that launch a real standalone VS Code instance, load the locally-built Logic Apps extension, open webviews, interact with form fields via Selenium WebDriver, and verify the wizard flow + designer functionality.
Not filesystem-only tests. Not @vscode/test-cli tests (those exist separately in src/test/e2e/).
1.5. Critical Rules — Read Before Writing Any New Test
These are the rules whose violation has caused entire test suites to be rewritten. Read them first.
Rule 1. Use Create Workspace + reopen — NEVER synthesize Logic App fixtures on disk
For any test that touches debug, the design-time API, the language server, the overview page, or anything that runs after a workspace opens:
- Create the workspace via the real Create Workspace webview in one
run-e2e.tsphase. - After it generates the
.code-workspace, end that VS Code session. - Open a fresh phase with the generated
.code-workspaceas theresourcesargument. - Wait for design-time startup evidence (e.g.,
workflow-designtime/) before any debug or designer assertion.
Why this matters: Hand-written project folders skip everything the wizard does — local.settings.json shape, .vscode/launch.json, extension activation order, project-type detection, language-server registration, the prompts that the extension expects to have already been answered. A synthetic fixture passes locally and fails in CI for invisible reasons, or worse, passes everywhere while testing a non-existent code path.
Exceptions (and ONLY these):
- Pure non-Logic-App smoke tests (e.g.,
nonLogicAppStartup.test.ts). - Standalone-runner unit tests that explicitly do not start VS Code.
Anti-precedents in this repo: createLegacyProjectFixture in run-e2e.ts exists because it predates this rule, and the former createCodefulProjectFixture was deleted after Phase 4.10 moved to Create Workspace + reopen. Do not use synthetic helpers as templates for new tests.
If the wizard helper does not yet support your project type, the correct fix is to extend createWorkspace.test.ts's helper to support the new appType, not to synthesize a fixture. The extension already supports codeful project creation via CreateLogicAppWorkspace.ts -> createCodefulWorkflowFile, and the E2E helper now exposes that flow for Phase 4.10.
Source: .squad/knowledge/vscode-e2e-testing.md — "Debug regressions need the real workspace and launch path".
Rule 2. One test per phase — fresh VS Code session
Tests sharing a Phase 4.x session fail due to lingering func.exe, language-server file locks, and webview iframes still in the DOM after a workspace switch. Every new test owns its own phase via prepareFreshSession().
Rule 3. Use Selenium Actions API for clicks inside webview iframes
Direct element.click() does not dispatch native events that React's synthetic event system captures. Use driver.actions().move({ origin: element }).click().perform().
Rule 4. Find inputs by label, not by DOM index
findInputByLabel('Workspace name') survives re-renders; index-based lookups silently write into the wrong field when the wizard reorders inputs.
Rule 5. Gate Next/Create clicks on validation success, not on button visibility
Webview validators are async. Wait for the button to be enabled and for error decorators to clear, not just for it to appear.
Rule 6. Lint and rebuild after every test edit
Run npx biome check --write <files> and npx tsup --config tsup.e2e.test.config.ts before claiming the test passes. Biome failures break CI; an un-rebuilt test runs the stale compiled JS.
2. File Inventory
| File | Purpose |
|---|---|
src/test/ui/nonLogicAppStartup.test.ts |
Plain-folder startup regression test. Phase 4.0 |
src/test/ui/bundleCdnHealth.test.ts |
CDN integrity probe (Content-Length + Content-MD5 on Microsoft.Azure.Functions.ExtensionBundle.Workflows). Pure Mocha — runs without VS Code. Phase 4.11 / E2E_MODE=bundleintegrityonly. |
src/test/ui/createWorkspace.test.ts |
Create Workspace wizard tests (~4359 lines). Phase 4.1 |
src/test/ui/designerActions.test.ts |
Designer full lifecycle tests (~2647 lines). Phase 4.2 |
src/test/ui/designerOpen.test.ts |
Designer open tests (~1100 lines). Deprecated — Phase 4.2 now uses designerActions.test.ts only |
src/test/ui/workspaceManifest.ts |
Shared manifest types and utilities (~110 lines) |
src/test/ui/run-e2e.ts |
Launcher script (~2600 lines). Orchestrates ExTester programmatically. Compiled by tsup to out/test/run-e2e.js |
src/test/ui/run-clean.ps1 |
PowerShell helper to kill stuck processes, compile, and run |
src/test/ui/smoke.test.ts |
Extension smoke tests |
src/test/ui/commands.test.ts |
Logic Apps command tests |
src/test/ui/basic.test.ts |
Extended UI interaction tests |
src/test/ui/demo.test.ts |
Basic VS Code functionality tests |
src/test/ui/standalone.test.ts |
Framework validation tests (no VS Code required) |
src/test/ui/SKILL.md |
This file |
out/test/*.test.js |
Compiled output (generated via tsup, do not edit) |
out/test/vscode-settings.json |
Generated VS Code settings (generated, do not edit) |
dist/test-extensions/ |
Isolated extensions directory used by ExTester (generated) |
3. How to Build & Run
# From: apps/vs-code-designer/
# 1. Build the extension (REQUIRED — creates dist/)
cd ../../ # repo root
pnpm run build:extension
cd apps/vs-code-designer
# 2. Compile the test TypeScript (uses tsup → CJS for Mocha)
npx tsup --config tsup.e2e.test.config.ts
# 3. Run all tests (Phase 4.0+)
node out/test/run-e2e.js
# 4. Run only Phase 4.2 (designer tests) using existing workspaces
$env:E2E_MODE="designeronly" # PowerShell
export E2E_MODE=designeronly # bash
node out/test/run-e2e.js
# 5. Run only the plain-folder startup regression test
$env:E2E_MODE="nonlogicappstartup" # PowerShell
export E2E_MODE=nonlogicappstartup # bash
node out/test/run-e2e.js
# Or use the PowerShell helper (kills stuck processes first):
powershell -ExecutionPolicy Bypass -File src/test/ui/run-clean.ps1
Build Scripts
pnpm run build:ui # Compiles test TypeScript via tsup → CJS
pnpm run test:ui # Runs node out/test/run-e2e.js
E2E_MODE Environment Variable
| Value | Behavior |
|---|---|
| (unset) | Runs Phase 4.0 (non-Logic-App startup), Phase 4.1 (createWorkspace), then later designer/conversion phases |
nonlogicappstartup |
Runs only Phase 4.0 with minimal settings and no runtime dependency paths |
designeronly |
Skips Phase 4.1, runs Phase 4.2 using workspaces from a previous Phase 4.1 run |
bundleintegrityonly |
Runs Phase 4.11 (bundleCdnHealth.test.ts) — pure-Mocha probe of cdn.functions.azure.com integrity headers. No VS Code session, no compiled extension required (only npx tsup --config tsup.e2e.test.config.ts). Bundled into the independentonly shard for CI. |
IMPORTANT: E2E_MODE=designeronly requires that Phase 4.1 has been run previously in the same session and workspaces still exist on disk. If the previous run's after() hook cleaned up workspaces, Phase 4.2 tests will fail with "Missing workspace directories" errors.
NOTE: When running from a background terminal, run from apps/vs-code-designer:
cd apps/vs-code-designer
node out/test/run-e2e.js
4. Architecture
4.1 Session Learnings (2026-02-26 through 2026-03-03)
Phase 4.2 rewrite (2026-02-27 → 2026-03-03)
The original Phase 4.2 had 15+ scattered tests across designerOpen.test.ts and designerActions.test.ts. These were replaced with 2 focused end-to-end tests in designerActions.test.ts only:
- Before: 15+ tests, 23-minute runtime, ~20% pass rate
- After: 2 tests, 5-minute runtime, ~80% pass rate (failures are the intermittent CustomCode designer loading issue)
Detection-based polling replaces static sleeps
All sleep(WAIT) patterns were replaced with polling functions:
waitForDesignerWebviewTab()— polls for webview iframe appearanceswitchToDesignerWebview()— 3-phase: iframe switch → spinner disappears → canvas + nodes renderwaitForDiscoveryPanel()— polls for panel elementwaitForSearchResults()— polls for result cardswaitForNodeCountIncrease()— polls for node count changeclickSaveButton()— polls for save completionwaitForRuntimeReady()— polls for debug toolbar + terminal outputwaitForRunStatusInList()— polls overview list with periodic Refresh
Command palette retry (5 attempts)
executeOpenDesignerCommand() retries up to 5 times with 3s delays. The extension needs time to re-register commands after a workspace switch. Also checks the return value of waitForDesignerWebviewTab() — if the webview didn't appear after the command was selected, the command silently failed and needs to be retried.
Selenium Actions API for React clicks
Direct .click() calls on elements inside webview iframes don't trigger React event handlers. All clicks on React elements use driver.actions().move({ origin: element }).click().perform() instead.
Debug + Overview + Run verification flow (2026-03-02 → 2026-03-03)
Added complete lifecycle verification:
- Debug: Start via command palette "Debug: Start Debugging". Wait for debug toolbar visible OR terminal output showing Functions runtime started.
- Overview: Switch to Explorer view (Ctrl+Shift+E), right-click workflow.json, select "Overview" from context menu. Close all editors first to ensure correct webview frame.
- Run trigger: Click "Run trigger" button in overview. Capture initial run status (Running or Succeeded).
- Verify: Refresh overview list until status shows "Succeeded". Then click into the run to open details. Verify all individual action nodes show "Succeeded".
Auth dialog bypass for testing
The overview page calls getAuthorizationToken() which shows a "wants to sign in" dialog. Added silentAuth setting in product code (getAuthorizationToken.ts). When azureLogicAppsStandard.silentAuth: true in VS Code settings, uses { silent: true } for session retrieval, preventing the blocking dialog.
Compose inputs field (Lexical editor)
The Compose action parameter panel uses a Lexical contenteditable editor, not a standard <input>. Found via [contenteditable="true"].editor-input selector. Must click to focus then sendKeys() to type. Required for save to succeed (empty Compose inputs causes validation failure).
Strict interaction policy now used in designerActions.test.ts
- Add-trigger and add-action tests now fail if operation selection does not succeed.
- Verification is based on semantic node presence on the canvas:
- Trigger flow asserts a
requestnode is visible. - Action flow asserts a
composenode is visible.
- Trigger flow asserts a
- The suite no longer treats “panel opened but operation not inserted” as pass-with-caveat for these core checks.
Discovery panel selection reliability improvements
selectOperation()now uses broader candidate matching across multiple selectors/roles plus text-based fallbacks.- Matching includes operation variants such as
When an HTTP request is receivedforrequest. - A guard blocks false positives such as selecting the
Allpseudo-result item.
Operational guidance from this session
- If Phase 4.2 reports missing workspace paths, re-run full
run-e2e.ts(withoutE2E_MODE) to regenerate fresh Phase 4.1 outputs before retrying designer tests. - If settings cleanup encounters file locks, clear stale VS Code test processes and retry with the existing cleanup fallback (
settings/Userdeletion path). - Use actions-only runs while iterating on discovery panel selectors, then promote to full Phase 4.2 once stable.
How ExTester Loads the Extension
ExTester cannot use --extensionDevelopmentPath reliably (it overrides EXTENSION_DEV_PATH to undefined unless coverage=true, and coverage=true adds a --coverage CLI flag that causes crashes). Instead:
- Copy
dist/→test-extensions/<publisher>.<name>-<version>/— makes it look like a marketplace-installed extension - Delete
.obsoletefile — VS Code creates this to mark extensions for removal; must be deleted or VS Code silently refuses to load the extension - Register in
extensions.json— manually-copied extensions need an entry withidentifier,version,location(URI), andrelativeLocation - Pass
--extensions-dirpointing to thetest-extensions/directory via ExTester's 3rd constructor arg
Key Invariant: No Auto-Update
VS Code will auto-update our old-versioned extension (5.110.0) from the marketplace (5.230.15+), creating duplicate commands in the command palette. This causes tests to select the wrong command.
Solution: The settings file (out/test/vscode-settings.json) disables auto-update:
{
"extensions.auto Update": false,
"extensions.autoCheckUpdates": false,
"update.mode": "none"
}
And run-e2e.ts removes any stale auto-updated versions of our extension on startup.
Test-Extensions Directory Structure
dist/test-extensions/
├── extensions.json ← VS Code reads this
├── ms-azuretools.vscode-azurelogicapps-5.110.0/ ← OUR extension (copied from dist/)
├── ms-azuretools.vscode-azurefunctions-1.20.3/ ← dependency
├── azurite.azurite-3.35.0/ ← dependency
├── ms-azuretools.vscode-azureresourcegroups-.../ ← dependency
├── ms-dotnettools.csharp-.../ ← dependency
└── ms-dotnettools.csdevkit-.../ ← dependency
5. Known Issues & Pitfalls (Debugging Guide)
Issue: .obsolete file blocks extension loading
Symptom: Extension host log shows no activation for our extension. Commands don't appear in palette.
Cause: VS Code writes {"ms-azuretools.vscode-azurelogicapps-5.110.0":true} to .obsolete in the extensions dir.
Fix: Delete .obsolete after copying extension. Already handled in run-e2e.ts.
Issue: Extension auto-updated from marketplace
Symptom: 5 command palette picks instead of expected 2-3. Errors reference 5.230.15/main.js instead of 5.110.0.
Cause: VS Code downloads newer version from marketplace, creating duplicate extension.
Fix: Set extensions.autoUpdate: false in VS Code settings. Remove stale versions in run-e2e.ts.
Issue: Wrong webview opened ("Create Workspace From Package")
Symptom: Webview shows "Package path" input. Tab title includes "From Package". Tests can't find expected fields. Cause: Two commands match "create workspace" search:
azureLogicAppsStandard.createWorkspace→ "Create new logic app workspace..." (CORRECT)azureLogicAppsStandard.cloudToLocal→ "Create new logic app workspace from package..." (WRONG) Fix: Filter picks to exclude labels containing "package". TherunCommandFromPalette()function does this.
Issue: EPERM on Windows during settings cleanup
Symptom: fs.removeSync fails with EPERM on settings/ directory.
Cause: Previous VS Code test process left locked cache files.
Fix: Pre-clean settings dir with fs.rmSync({recursive:true, force:true, maxRetries:3}).
Issue: Test file glob doesn't match on Windows
Symptom: 0 passing, 0 failing.
Cause: path.resolve() produces backslashes on Windows; ExTester's glob matching expects forward slashes.
Fix: .replace(/\\/g, '/') on the test glob path.
Issue: Command palette setText() clears the > prefix
Symptom: All command palette searches return "No matching results", even though the extension is loaded.
Cause: VS Code's command palette prefixes the input with > to indicate command mode. ExTester's InputBox.setText() calls clear() first, which removes the >. Without >, VS Code treats input as a file search, so no commands appear.
Fix: Always prefix search text with > when using setText() in the command palette:
await input.setText('> logic app workspace'); // ✅ stays in command mode
await input.setText('logic app workspace'); // ❌ switches to file search
Issue: Locked files from previous test run (EBUSY)
Symptom: Error: EBUSY: resource busy or locked, unlink '...\exthost.log' in "before all" hook.
Cause: Previous test VS Code instances left child processes running (Roslyn Language Server, Azure Deployment Express Language Server, JSON Language Server, etc.) that hold file locks in test-resources/settings/logs/. The vscode.openFolder(uri, true) call (triggered by Create Workspace) spawns an entirely new VS Code window whose language servers persist after the test driver shuts down.
Fix (multi-layered):
- Kill ALL instances of known language server executables by name
- WMIC search for processes with
test-resourcesin command line →taskkill /F /T - Wait 5 seconds after killing for handles to release
- 5-attempt retry loop with 3s delays for
fs.rmSyncon settings dir - Smart fallback: If full
settings/delete fails, delete justsettings/User - Last resort: rename to
settings-stale-<timestamp>
Issue: Tests pass but silently swallow errors
Symptom: All tests show ✔ but actual assertions fail (visible in console output as caught errors).
Cause: Many tests wrap everything in try/catch and just log the error instead of failing.
Status: KNOWN ISSUE. These need to be tightened — remove try/catch wrappers and let failures propagate.
Issue: Notification toasts block webview interaction
Symptom: ElementClickInterceptedError when trying to interact with webview. A notification toast covers the element.
Cause: Extension activation (especially dependency extensions like C# DevKit) displays notifications.
Fix: dismissNotifications(driver) helper clicks notification close buttons before interacting with the webview.
Issue: Label ambiguity — "Function name" matches "Function namespace"
Symptom: Custom code fields filled incorrectly — namespace gets the function name value, function name stays empty.
Cause: XPath contains(text(), 'Function name') matches BOTH "Function name" and "Function namespace".
Fix: Use exclusive XPath matching: //label[contains(text(), 'Function name') and not(contains(text(), 'namespace'))]
Issue: Namespace validation mismatch (PRODUCT BUG)
Symptom: All custom code fields filled correctly, but Next button remains disabled. No visible validation error.
Cause: In createWorkspace.tsx, canProceed() validates function namespace using nameValidation regex, which does NOT allow dots. But the field's own inline validation uses namespaceValidation which DOES allow dots.
Workaround: Use dot-free namespaces in tests.
Product fix needed: canProceed() should use namespaceValidation for the namespace field.
Issue: Function name validation allows hyphens (PRODUCT BUG — FIXED)
Symptom: Generated .cs files contain invalid C# identifiers like public class myfunc-abc.
Cause: The webview wizard's nameValidation regex (/^[a-z][a-z0-9]*(?:[_-][a-z0-9]+)*$/i) was shared for ALL name fields including C# function names. Hyphens are invalid in C# identifiers.
Root cause locations:
apps/vs-code-react/src/app/createWorkspace/validation/helper.ts— shared regex for all namesapps/vs-code-designer/src/app/commands/createNewCodeProject/CodeProjectBase/CreateFunctionAppFiles.ts— no sanitization before template substitutionapps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/functionAppFilesStep.ts— sameapps/vs-code-designer/src/app/commands/createCustomCodeFunction/createCustomCodeFunctionSteps/functionFileStep.ts— same Fix applied (2026-02-24):
- Added
functionNameValidation = /^[a-z][a-z\d_]*$/iinhelper.ts— dedicated regex that rejects hyphens - Updated
validateFunctionName()to usefunctionNameValidationinstead ofnameValidation - Added
.replace(/-/g, '_')sanitization in all 3 template rendering locations (defense-in-depth) - Updated error message to say "letters, digits, and underscores" (removed hyphen mention)
- Fixed E2E test
uniqueName()to use underscores instead of hyphens - Added 47 unit tests in
apps/vs-code-react/src/app/createWorkspace/validation/__test__/helper.test.tsNote: The old command-palette wizard (functionAppNameStep.ts) already correctly used/^[a-z][a-z\d_]*$/iand rejected hyphens. The bug was only in the new webview wizard.
Issue: Azure connector wizard blocks designer loading (FIXED)
Symptom: Designer never loads for CustomCode and RulesEngine workspaces. VS Code shows QuickPick prompts that require manual intervention.
Cause: When WORKFLOWS_SUBSCRIPTION_ID is undefined in local.settings.json, the extension shows two blocking QuickPick prompts:
- "Enable connectors in Azure for Logic App" → "Use connectors from Azure" / "Skip for now"
- "Select authentication method for Azure connectors" → "Managed Service Identity" / "Connection Keys"
Code path:
getAzureConnectorDetailsForLocalProject()inapps/vs-code-designer/src/app/utils/codeless/common.tstriggersazureConnectorWizard.tswhich callsauthenticationMethodStep.ts. Fix applied (2026-02-24): Two-layer fix in bothdesignerOpen.test.tsanddesignerActions.test.ts: ensureLocalSettingsForDesigner(appDir)— patcheslocal.settings.jsonwithWORKFLOWS_SUBSCRIPTION_ID: ""before opening the designer. Setting it to empty string (not undefined) prevents the wizard from launching.handleDesignerPrompts(workbench, driver)— fallback safety net that polls for QuickPick dialogs and auto-selects "Skip for now" / "Connection Keys" if they still appear. Standard workspaces already hadWORKFLOWS_SUBSCRIPTION_ID: ""in theirlocal.settings.json(set by the creation wizard), so they were unaffected.
Issue: Command palette fails to open in designer tests (FIXED)
Symptom: Waiting for element to be located By(css selector, .quick-input-widget) Wait timed out after 5xxxms — affects all tests that call executeOpenDesignerCommand().
Cause: workbench.openCommandPrompt() (ExTester API) intermittently fails to open the command palette after workspace switching.
Fix applied (2026-02-27): executeOpenDesignerCommand() now retries up to 5 times with 3s delays. Before each attempt, it clears blocking UI (dialogs, notifications), dismisses JS dialogs, and focuses the editor. Additionally, after pick.select(), it checks whether waitForDesignerWebviewTab() actually found a webview — if not, it retries the command (the command may have silently failed).
Issue: Auth dialog blocks overview page loading (FIXED)
Symptom: Overview page shows sign-in dialog "Azure Logic Apps wants to sign in using Microsoft". Test hangs waiting for overview content.
Cause: openOverview.ts calls getAuthorizationToken() which uses { createIfNone: true }, triggering an interactive auth dialog.
Code path: getAuthorizationToken.ts → getSessionFromVSCode() → vscode.authentication.getSession() with createIfNone: true.
Fix applied (2026-03-02): Added silentAuth setting support in getAuthorizationToken.ts. When azureLogicAppsStandard.silentAuth is true in VS Code settings, uses { silent: true } instead of { createIfNone: true }. This returns undefined if no session exists (instead of prompting), and the overview page handles the missing token gracefully.
Issue: Wrong webview frame entered for overview (FIXED)
Symptom: switchToOverviewWebview() enters the designer iframe instead of the overview iframe.
Cause: If the designer webview tab is still open when the overview opens, ExTester's WebView.switchToFrame() targets the first matching iframe, which is the designer.
Fix applied (2026-03-02): Added editorView.closeAllEditors() before opening the overview page. This ensures only the overview webview exists when switchToFrame() is called.
Issue: Debug view blocks Explorer right-click (FIXED)
Symptom: After starting debugging, right-click on workflow.json in Explorer fails because the Activity Bar shows the Debug view instead of Explorer.
Fix applied (2026-03-02): Added Ctrl+Shift+E keyboard shortcut to switch back to Explorer view before attempting the right-click.
Issue: CustomCode designer content doesn't render (ACTIVE)
Symptom: Designer webview tab appears, switchToFrame() succeeds, but Phase 2: spinner still present or #root not found after 75s. React content never mounts inside the webview.
Cause: Unknown. Happens ~30% of the time for CustomCode workspaces, particularly when they are the second workspace loaded in a test session (after Standard). May be resource contention from previous debug session's func.exe or language servers not fully releasing.
Impact: Test 2 fails intermittently at the "Add-action button or trigger card should be visible" assertion because the designer canvas never renders.
Potential fixes:
- Add longer cleanup wait between test 1 and test 2
- Explicitly kill func.exe between tests
- Close all editors and wait for VS Code to fully settle after workspace switch
- Increase Phase 2 timeout beyond 75s (though the real issue is the content never appearing)
Issue: CustomCode workspaces missing workflow.json
Symptom: workflow.json not found: .../ccapp-mm1b0gh2/ccwf-mm1b0gh2/workflow.json
Cause: For CustomCode workspaces, the workflow directory structure differs — but the manifest's wfDir path is based on the naming convention from createWorkspace.test.ts which may not match the actual directory created by the wizard.
Also: Previous test run's after() hook partially cleaned up workspaces, leaving some in a corrupted state.
Impact: All CustomCode designer tests fail at the "verify workflow.json exists" step.
Fix needed: Re-run Phase 4.1 to create fresh workspaces, and verify the manifest paths match actual disk layout.
Issue: Stale workspaces from previous test runs
Symptom: E2E_MODE=designeronly tests fail with "Missing workspace directories" for several workspace types.
Cause: The after() hook in designerOpen.test.ts calls cleanupAllWorkspaces() which deletes workspace directories. If Phase 4.2 is re-run after cleanup, the workspaces no longer exist.
Impact: Tests 1, 2, 6-9 fail in Phase 4.2 (workspace structure verification).
Fix: Always run Phase 4.1 (createWorkspace) before Phase 4.2 to ensure fresh workspaces. The run-e2e.ts script does this automatically when E2E_MODE is not set.
Issue: openFileInEditor() via Quick Open is unreliable
Symptom: "Failed to open workflow.json" errors when using the old InputBox-based Quick Open approach.
Cause: ExTester's workbench.openCommandPrompt() + setText(filePath) approach doesn't work reliably for opening files — Quick Open doesn't support absolute paths, and "Open File" triggers a native OS dialog that Selenium can't interact with.
Fix applied (2026-02-24): Replaced with VSBrowser.instance.openResources(filePath) in both test files. This is the ExTester-supported way to open files and reliably makes them the active editor tab.
Issue: openWorkspaceFileInSession() insufficient wait time
Symptom: Extension not ready after workspace switch — commands fail, webview doesn't appear. Cause: Original wait was only 4s. After switching workspaces, VS Code needs time to: close the old workspace, load the new workspace file, discover logic app folders, activate the extension, register commands. Fix applied (2026-02-24): Increased to 8s wait + element check + 5s stabilization in both test files.
6. React Webview Form Structure
The createWorkspace command opens a webview with the React wizard. Understanding this structure is essential for writing correct selectors.
Two-Step Wizard
| Step | Component | What's Shown |
|---|---|---|
| 0 | ProjectSetupStep |
All form fields (4 sub-components) |
| 1 | ReviewCreateStep |
Read-only summary + "Create workspace" button |
Step 0 Sub-Components (in order)
WorkspaceNameStep
| Field | Type | Label | Placeholder | Notes |
|---|---|---|---|---|
| Parent folder | Input + Browse button | Workspace parent folder path |
(none) | Required. Must be valid existing path |
| Workspace name | Input | Workspace name |
(none) | Required. Regex: /^[a-z][a-z0-9]*(?:[_-][a-z0-9]+)*$/i |
LogicAppTypeStep
| Field | Type | Label | Placeholder | Notes |
|---|---|---|---|---|
| Logic app name | Input | Logic app name |
Enter logic app name |
Required |
| Logic app type | Radio group | (3 options) | — | Default: Standard |
Radio options:
Logic app (Standard)→ valuelogicAppLogic app with custom code→ valuecustomCodeLogic app with rules engine→ valuerulesEngine
DotNetFrameworkStep (conditional — only for customCode or rulesEngine)
| Field | Type | Label | Notes |
|---|---|---|---|
| .NET Version | Dropdown | .NET Version |
Placeholder: Select .NET version |
| Folder name | Input | Custom code folder name or Rules engine folder name |
Depends on type |
| Function namespace | Input | Function namespace |
Required |
| Function name | Input | Function name |
Required |
WorkflowTypeStep
| Field | Type | Label | Placeholder | Notes |
|---|---|---|---|---|
| Workflow name | Input | Workflow name |
Enter workflow name |
Required |
| Workflow type | Dropdown | Workflow type |
Select workflow type |
Required |
Dropdown options:
Stateful(value:Stateful-Codeless)Stateless(value:Stateless-Codeless)Autonomous Agents (Preview)(value:Agentic-Codeless)Conversational Agents(value:Agent-Codeless)
Step 1 — ReviewCreateStep
Read-only summary table. Buttons: Back, Create workspace.
Navigation Buttons
- Step 0:
Back(disabled),Next - Step 1:
Back,Create workspace
Panel Titles (Tab Names)
createWorkspacecommand → Panel title: "Create Workspace"cloudToLocalcommand → Panel title: "Create Workspace From Package"
7. Selenium Selectors Reference
Finding inputs by label
Fluent UI renders <Label htmlFor={id}> + <Input id={id}>. Find label by text, read for attribute, then find input by id.
Finding radio buttons
Fluent UI v9 radios: input[type="radio"] exists but may be hidden. Click the <label> element instead.
Finding dropdowns
Fluent UI Dropdown renders a <button role="combobox"> as the trigger. Options are [role="option"] elements (may be portaled outside the immediate parent).
Webview iframe switching
Must call webview.switchToFrame(timeout) before any element interaction. Must call webview.switchBack() before interacting with VS Code chrome.
8. Extension Dependencies
These are installed from the marketplace into test-extensions/:
ms-azuretools.vscode-azurefunctionsazurite.azuritems-azuretools.vscode-azureresourcegroupsms-dotnettools.csharpms-dotnettools.csdevkit
9. Timing Constants
| Constant | Value | Why |
|---|---|---|
VSCODE_STARTUP_MS |
20s | Wait for VS Code chrome to render |
EXTENSION_READY_TIMEOUT_MS |
120s | Poll until extension activates and registers commands |
DESIGNER_TAB_TIMEOUT |
30s | Wait for designer webview tab to appear after command |
DESIGNER_READY_TIMEOUT |
75s | Wait for designer content to render (3-phase detection) |
PROJECT_RECOGNITION_WAIT |
5s | Wait for extension to recognize the workspace after file open |
TEST_TIMEOUT |
180s | Per-test Mocha timeout |
RUNTIME_READY_TIMEOUT |
90s | Wait for Functions runtime to start during debug |
OVERVIEW_WEBVIEW_TIMEOUT |
60s | Wait for overview webview to load |
RUN_STATUS_TIMEOUT |
30s | Wait for run to reach target status in overview list |
10. What Works (as of last run: 2026-02-24)
Phase 4.1 — Create Workspace (63 passing, 1 failing)
Runtime: ~10 minutes
- ✅ Extension loading via copy-to-test-extensions
- ✅
.obsoletefile cleanup - ✅
extensions.jsonregistration - ✅ ExTester downloads VS Code + ChromeDriver
- ✅ Extension dependencies installed from marketplace
- ✅ Command palette search finds picks (with retry logic)
- ✅ Correct webview detected (rejects "From Package")
- ✅ Webview opens and
switchToFrame()succeeds (with notification dismissal + 3 retries) - ✅ ALL standard form fields filled (path, workspace name, logic app name, radio, workflow name, workflow type)
- ✅ ALL custom code fields filled (.NET Version, folder name, namespace, function name)
- ✅ Review step verification (navigate forward, check summary, navigate back, values preserved)
- ✅ Workspace creation — clicks "Create workspace" button, waits for extension processing
- ✅ Disk verification — workspace dir, .code-workspace file, logic app dir, workflow dir
- ✅ Custom code disk verification — includes custom code folder
- ✅ EBUSY cleanup with multi-layered process killing
- ✅ afterEach recovery from
vscode.openFolderdriver state changes - ✅ 12 workspace types: Standard Stateful/Stateless/Agent/Conversational × Codeless/CustomCode
- ✅ Workspace manifest (
created-workspaces.json) persisted with workspace metadata for Phase 4.2
1 failing: Custom Code Stateful namespace validation (pre-existing product bug — canProceed() uses wrong regex)
Phase 4.2 — Designer Tests (2 passing, 0 failing)
Runtime: ~5 minutes
Phase 4.2 runs only designerActions.test.ts (the designerOpen.test.ts file was removed from Phase 4.2 runs). It contains 2 focused end-to-end tests that cover the complete workflow lifecycle:
Test 1: Standard Workflow (Stateful)
- Reset workflow.json to empty state
- Open designer via command palette (with 5-attempt retry)
- Wait for 3-phase designer loading (iframe → spinner gone → canvas + nodes)
- Add Request trigger via discovery panel search
- Add Response action via add-action button
- Save workflow and verify workflow.json on disk
- Start debugging via "Debug: Start Debugging" command palette
- Wait for Functions runtime to start (debug toolbar + terminal detection)
- Open overview page via Explorer right-click on workflow.json
- Click "Run trigger" button
- Verify run shows in overview list (capture "Running" or "Succeeded" state)
- Refresh until run shows "Succeeded" in overview list
- Click into the succeeded run to open run details
- Verify all action nodes show "Succeeded" status
Test 2: CustomCode Workflow (Stateful)
- Open CustomCode workspace and workflow.json
- Open designer (with command palette retry + webview tab detection)
- Add Compose action via discovery panel search
- Fill Compose inputs field (Lexical contenteditable editor)
- Save workflow and verify workflow.json on disk
- Start debugging and wait for runtime ready
- Open overview page
- Click "Run trigger"
- Verify run shows "Running" → transitions to "Succeeded" in overview list
- Open run details and verify all action nodes succeeded
Key helper functions in designerActions.test.ts (~2647 lines):
| Function | Purpose |
|---|---|
waitForDependencyValidation() |
Polls up to 120s for extension activation + command registration |
executeOpenDesignerCommand() |
Command palette with 5-attempt retry, dismisses blocking UI before each attempt |
waitForDesignerWebviewTab() |
Polls for webview iframe appearance with dialog/QuickPick handling |
switchToDesignerWebview() |
3-phase detection: iframe switch → spinner gone → canvas + nodes rendered |
selectOperation() |
Selenium Actions API click with broad candidate matching and StaleElement retry |
clickSaveButton() |
Polls for save completion (button re-enabling) |
readWorkflowJson() |
Disk verification of saved workflow.json |
startDebugging() |
Command palette "Debug: Start Debugging" |
waitForRuntimeReady() |
Debug toolbar detection + terminal output fallback (90s timeout) |
openOverviewPage() |
Explorer view → right-click workflow.json → context menu "Overview" |
switchToOverviewWebview() |
Frame switching with periodic auth dialog dismissal |
clickRunTrigger() |
Polls for enabled "Run trigger" button |
getLatestRunStatus() |
Reads status of topmost run in overview list |
waitForRunStatusInList() |
Polls overview list (with Refresh) until target status appears |
clickLatestRunRow() |
Opens the latest run's details view |
verifyAllNodesSucceeded() |
Checks all action nodes in run details show "Succeeded" |
stopDebugging() |
Sends Shift+F5 to stop debug session |
Product code change for testing:
getAuthorizationToken.ts: AddedsilentAuthsetting support. WhenazureLogicAppsStandard.silentAuthistrue, uses{ silent: true }instead of{ createIfNone: true }for Azure session, preventing the "wants to sign in" dialog that blocks overview page loading in test environments.
Test Inventory (All Phases Combined: 87+ passing, 1 failing)
Phase 4.1 — createWorkspace.test.ts (63 pass, 1 fail)
| Suite | # | Tests | Status |
|---|---|---|---|
| VS Code Basic | 5 | VS Code title, activity bar, sidebar, editor, instance | ✅ |
| Smoke Tests | 5 | VS Code load, activity bar, command palette, search, explorer | ✅ |
| Simple Suite | 4 | Basic assertions (math, string, array, async) | ✅ |
| Create Workspace (non-destructive) | 6 | Command selection, form values, workflow types, step indicator, button states | ✅ |
| Create Workspace (destructive) | 48 | 12 workspace types × 4 tests each (creation, disk verify, workspace file, manifest) | 47 ✅, 1 ❌ |
Phase 4.2 — designerActions.test.ts + new tests (8+ pass, 0 fail)
| Suite | # | Tests | Status | ADO ID |
|---|---|---|---|---|
| Designer Actions | 1 | Standard workflow: trigger + response + save + debug + overview + run | ✅ | |
| Designer Actions | 1 | CustomCode workflow: add compose + fill inputs + save + debug + overview + run | ✅ | |
| Inline JavaScript | 1 | Request trigger + Execute JS Code + Response → save + debug + run + verify | 🆕 | #10109800 |
| Stateless Variables | 1 | Stateless workflow + Request trigger + Initialize Variable + Response → full flow | 🆕 | #10109878 |
| Designer View Extended | 1 | Add parallel branch alongside existing action | 🆕 | #10109401 |
| Designer View Extended | 1 | Configure run-after settings on an action | 🆕 | #10109401 |
| Keyboard Navigation | 1 | Ctrl+Down/Up navigation between canvas nodes | 🆕 | #10273324 |
Phase 4.3 — smoke/demo/standalone + Data Mapper (16+ pass, 0 fail)
| Suite | # | Tests | Status | ADO ID |
|---|---|---|---|---|
| Demo, Smoke, Standalone | 14 | Generic VS Code functionality, framework validation | ✅ | |
| Data Mapper Extension | 1 | Open Data Mapper from Azure activity bar | 🆕 | #26272218 |
| Data Mapper Extension | 1 | Verify "Create new data map" command exists | 🆕 | #26272218 |
11. What Needs Work (Prioritized)
P0: Fix intermittent CustomCode designer loading failure
Impact: Te
…(truncated)