# Azure Logicappsux Logicappsux

> Skill: ExTester UI E2E Tests for VS Code Logic Apps Extension

- Skill: `tomevault-io/azure-logicappsux-logicappsux` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/azure-logicappsux-logicappsux`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/azure-logicappsux-logicappsux/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/azure-logicappsux-logicappsux

---

# 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:

1. Create the workspace via the real **Create Workspace** webview in one `run-e2e.ts` phase.
2. After it generates the `.code-workspace`, end that VS Code session.
3. Open a fresh phase with the generated `.code-workspace` as the `resources` argument.
4. 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

```bash
# 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

```bash
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`:
```bash
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 appearance
- `switchToDesignerWebview()` — 3-phase: iframe switch → spinner disappears → canvas + nodes render
- `waitForDiscoveryPanel()` — polls for panel element
- `waitForSearchResults()` — polls for result cards
- `waitForNodeCountIncrease()` — polls for node count change
- `clickSaveButton()` — polls for save completion
- `waitForRuntimeReady()` — polls for debug toolbar + terminal output
- `waitForRunStatusInList()` — 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:
1. **Debug**: Start via command palette "Debug: Start Debugging". Wait for debug toolbar visible OR terminal output showing Functions runtime started.
2. **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.
3. **Run trigger**: Click "Run trigger" button in overview. Capture initial run status (Running or Succeeded).
4. **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 `request` node is visible.
  - Action flow asserts a `compose` node is visible.
- 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 received` for `request`.
- A guard blocks false positives such as selecting the `All` pseudo-result item.

### Operational guidance from this session

- If Phase 4.2 reports missing workspace paths, re-run full `run-e2e.ts` (without `E2E_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/User` deletion 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:

1. **Copy `dist/` → `test-extensions/<publisher>.<name>-<version>/`** — makes it look like a marketplace-installed extension
2. **Delete `.obsolete` file** — VS Code creates this to mark extensions for removal; must be deleted or VS Code silently refuses to load the extension
3. **Register in `extensions.json`** — manually-copied extensions need an entry with `identifier`, `version`, `location` (URI), and `relativeLocation`
4. **Pass `--extensions-dir`** pointing to the `test-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:
```json
{
  "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". The `runCommandFromPalette()` 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:
```typescript
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)**:
1. Kill ALL instances of known language server executables by name
2. WMIC search for processes with `test-resources` in command line → `taskkill /F /T`
3. Wait 5 seconds after killing for handles to release
4. 5-attempt retry loop with 3s delays for `fs.rmSync` on settings dir
5. **Smart fallback**: If full `settings/` delete fails, delete just `settings/User`
6. 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 names
  - `apps/vs-code-designer/src/app/commands/createNewCodeProject/CodeProjectBase/CreateFunctionAppFiles.ts` — no sanitization before template substitution
  - `apps/vs-code-designer/src/app/commands/createProject/createCustomCodeProjectSteps/functionAppFilesStep.ts` — same
  - `apps/vs-code-designer/src/app/commands/createCustomCodeFunction/createCustomCodeFunctionSteps/functionFileStep.ts` — same
**Fix applied (2026-02-24)**:
  1. Added `functionNameValidation = /^[a-z][a-z\d_]*$/i` in `helper.ts` — dedicated regex that rejects hyphens
  2. Updated `validateFunctionName()` to use `functionNameValidation` instead of `nameValidation`
  3. Added `.replace(/-/g, '_')` sanitization in all 3 template rendering locations (defense-in-depth)
  4. Updated error message to say "letters, digits, and underscores" (removed hyphen mention)
  5. Fixed E2E test `uniqueName()` to use underscores instead of hyphens
  6. Added 47 unit tests in `apps/vs-code-react/src/app/createWorkspace/validation/__test__/helper.test.ts`
**Note**: The old command-palette wizard (`functionAppNameStep.ts`) already correctly used `/^[a-z][a-z\d_]*$/i` and 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:
  1. "Enable connectors in Azure for Logic App" → "Use connectors from Azure" / "Skip for now"
  2. "Select authentication method for Azure connectors" → "Managed Service Identity" / "Connection Keys"
**Code path**: `getAzureConnectorDetailsForLocalProject()` in `apps/vs-code-designer/src/app/utils/codeless/common.ts` triggers `azureConnectorWizard.ts` which calls `authenticationMethodStep.ts`.
**Fix applied (2026-02-24)**: Two-layer fix in both `designerOpen.test.ts` and `designerActions.test.ts`:
  1. `ensureLocalSettingsForDesigner(appDir)` — patches `local.settings.json` with `WORKFLOWS_SUBSCRIPTION_ID: ""` before opening the designer. Setting it to empty string (not undefined) prevents the wizard from launching.
  2. `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 had `WORKFLOWS_SUBSCRIPTION_ID: ""` in their `local.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**:
  1. Add longer cleanup wait between test 1 and test 2
  2. Explicitly kill func.exe between tests
  3. Close all editors and wait for VS Code to fully settle after workspace switch
  4. 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)` → value `logicApp`
- `Logic app with custom code` → value `customCode`
- `Logic app with rules engine` → value `rulesEngine`

#### 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)
- `createWorkspace` command → Panel title: **"Create Workspace"**
- `cloudToLocal` command → 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/`:
1. `ms-azuretools.vscode-azurefunctions`
2. `azurite.azurite`
3. `ms-azuretools.vscode-azureresourcegroups`
4. `ms-dotnettools.csharp`
5. `ms-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
- ✅ `.obsolete` file cleanup
- ✅ `extensions.json` registration
- ✅ 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.openFolder` driver 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)**
1. Reset workflow.json to empty state
2. Open designer via command palette (with 5-attempt retry)
3. Wait for 3-phase designer loading (iframe → spinner gone → canvas + nodes)
4. Add Request trigger via discovery panel search
5. Add Response action via add-action button
6. Save workflow and verify workflow.json on disk
7. Start debugging via "Debug: Start Debugging" command palette
8. Wait for Functions runtime to start (debug toolbar + terminal detection)
9. Open overview page via Explorer right-click on workflow.json
10. Click "Run trigger" button
11. Verify run shows in overview list (capture "Running" or "Succeeded" state)
12. Refresh until run shows "Succeeded" in overview list
13. Click into the succeeded run to open run details
14. Verify all action nodes show "Succeeded" status

**Test 2: CustomCode Workflow (Stateful)**
1. Open CustomCode workspace and workflow.json
2. Open designer (with command palette retry + webview tab detection)
3. Add Compose action via discovery panel search
4. Fill Compose inputs field (Lexical contenteditable editor)
5. Save workflow and verify workflow.json on disk
6. Start debugging and wait for runtime ready
7. Open overview page
8. Click "Run trigger"
9. Verify run shows "Running" → transitions to "Succeeded" in overview list
10. 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`: Added `silentAuth` setting support. When `azureLogicAppsStandard.silentAuth` is `true`, 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)
