Skip to content

feat(lwc): add LWC LSP Playwright E2E test suite with web + desktop coverage W-22187438#7248

Open
madhur310 wants to merge 3 commits intodevelopfrom
ms/lls-playwright-e2e
Open

feat(lwc): add LWC LSP Playwright E2E test suite with web + desktop coverage W-22187438#7248
madhur310 wants to merge 3 commits intodevelopfrom
ms/lls-playwright-e2e

Conversation

@madhur310
Copy link
Copy Markdown
Collaborator

@madhur310 madhur310 commented Apr 23, 2026

Add six new headless Playwright specs covering LWC language server features
(indexing, SFDX typings generation, autocompletion, go-to-definition for HTML
and JS, and custom components index). Include CI workflow
(lwcPlaywrightE2E.yml), shared test utilities (lwcUtils.ts,
createLwcTestWorkspace.ts, lwcWebScratchAuth.ts), and all supporting
changes to playwright-vscode-ext, salesforcedx-lwc-language-server, and
salesforcedx-vscode-services needed to make both web and desktop runs stable.

Key fixes bundled with the new specs:

  • VS Code 1.117.0 Quick Open format change: pass leaf filename only to openFileByName so openSfdxCustomComponentsJson and assertLwcSfdxTypingsGenerated resolve correctly on desktop
  • TS 6.x Go-to-Definition behaviour: hover over the LightningElement import token to force type resolution, then Meta+click; wait for the hover tooltip to confirm TS is ready before navigation fires (fixes flakiness under parallel test load)
  • SFDX Create LWC wizard: handle optional component-type picker introduced in newer extension versions using QUICK_INPUT_LIST_ROW locator
  • lwcSnippets web stability: remove unreliable window reload; use deploy-on-save timing instead

What does this PR do?

What issues does this PR fix or reference?

@W-22187438@

Functionality Before

<insert gif and/or summary>

Functionality After

<insert gif and/or summary>

…overage - W-22187438

  Add six new headless Playwright specs covering LWC language server features
  (indexing, SFDX typings generation, autocompletion, go-to-definition for HTML
  and JS, and custom components index). Include CI workflow
  (lwcPlaywrightE2E.yml), shared test utilities (lwcUtils.ts,
  createLwcTestWorkspace.ts, lwcWebScratchAuth.ts), and all supporting
  changes to playwright-vscode-ext, salesforcedx-lwc-language-server, and
  salesforcedx-vscode-services needed to make both web and desktop runs stable.

  Key fixes bundled with the new specs:
  - VS Code 1.117.0 Quick Open format change: pass leaf filename only to
    openFileByName so openSfdxCustomComponentsJson and
    assertLwcSfdxTypingsGenerated resolve correctly on desktop
  - TS 6.x Go-to-Definition behaviour: hover over the LightningElement import
    token to force type resolution, then Meta+click; wait for the hover tooltip
    to confirm TS is ready before navigation fires (fixes flakiness under
    parallel test load)
  - SFDX Create LWC wizard: handle optional component-type picker introduced in
    newer extension versions using QUICK_INPUT_LIST_ROW locator
  - lwcSnippets web stability: remove unreliable window reload; use
    deploy-on-save timing instead
@madhur310 madhur310 changed the title feat(lwc): add LWC LSP Playwright E2E test suite with web + desktop c… feat(lwc): add LWC LSP Playwright E2E test suite with web + desktop coverage W-22187438 Apr 23, 2026
@madhur310 madhur310 marked this pull request as ready for review April 23, 2026 21:33
@madhur310 madhur310 requested a review from a team as a code owner April 23, 2026 21:33
@madhur310 madhur310 requested review from mshanemc and randi274 and removed request for randi274 April 23, 2026 21:33

1. Branch: `feature/my-branch`
2. Find "Metadata E2E (Playwright)" `in_progress`
2. Find "Metadata E2E (Playwright)" or "LWC E2E (Playwright)" `in_progress`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need to doc every one, the example is the same

// Always start fresh. Reusing run:web (port 3001) causes EPIPE/premature close when test process
// expects to control the server lifecycle.
reuseExistingServer: false
// CI: always spawn headlessServer so runs are isolated. Local (`reuseExistingServer: !process.env.CI`): if 3001
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I had problems with this in the past, but if it works fine locally now that's great.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems to work right now.

* Call before {@link closeWelcomeTabs} so specs do not race an empty tab strip.
* No-op on desktop: an opened-folder workspace often has no Welcome tab.
*/
export const assertWelcomeTabExists = async (page: Page): Promise<void> => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems weird that NO other web test needed/had this before. Still need it?

interface CustomLabelsXml {
CustomLabels?: {
labels?: { fullName: string[] }[];
/** xml2js: one `<labels>` → object; multiple → array of objects */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes things a lot simpler than isArray handling

// strip-ansi: import fails (TS2306/TS1479); require works for both v5 and v7
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment
const stripAnsi = require('strip-ansi');
const stripAnsi: (input: string) => string = require('strip-ansi');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's so ugly. node has native for that stripVTControlCharacters

I wonder if our utils polyfill also has that? You could find out and then maybe get rid of this and the dep

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or if it's just used for desktop (since no tests on web) we don't care and native node alone is enough?

const { definition } = execution.task;
const { sfTaskId } = definition;
if (sfTaskId) {
if (typeof sfTaskId === 'string') {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meta for this whole file...what's this for?

I remember some slack threads where we discussed getting rid of other Task-ish stuff?
#6841

};

/** Path-string workspace detection fails for some virtual/test-web roots; `workspace.fs` uses the folder URI. */
const rootHasSfdxProjectJson = async (folderUri: URI): Promise<boolean> => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can it use projectService.isSalesforceProject

* Web / multi-root: expand a folder path in Files Explorer (`mount/` prefix when test-web presents that root).
* Reused for LWC bundles under `force-app/.../lwc` and for `.sfdx/typings/lwc` generated typings.
*/
const expandWebExplorerSegments = async (page: Page, pathSegments: string[]): Promise<void> => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the complexity of this is coming from using the mount folder stuff.

It would be much better to test these types of things using the web IDEs file system instead of a locally mounted file system, because so much of the interesting stuff we have probably relates to paths, and those behave differently.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another potential option would be to create an org that has all the stuff you want in it (there's a script for setting up dreamhouse in a scratch org already) And then you could retrieve your metadata so that your project gets the way you want it. And then you could run all the the stuff. And that way you're using the real web fs.

const PUSH_OR_DEPLOY_ON_SAVE_ENABLED = 'push-or-deploy-on-save.enabled';

/**
* VS Code for Web (Code Builder) does not use local CLI auth files. Injects scratch `instanceUrl` and `accessToken`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly true. It gets the instance URL and access token because that's what we would receive from core. And then it auths and having auth files locally is a byproduct of that. So you do end up with auth files, you just can't see them in the project.

*
* Local: reuse `orgBrowserDreamhouseTestOrg` or override with `DREAMHOUSE_ORG_ALIAS`. CI: provision the same org as org-browser E2E.
*/
export const applyLwcWebScratchAuth = async (page: Page): Promise<void> => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see upsertScratchOrgAuthFieldsToSettings in the playwright ext

/**
* Create bundles with **SFDX: Create Lightning Web Component** (same FS the UI uses), then open the `.js` editor.
*/
export const createLwcViaSfdxCommand = async (page: Page, componentName: string): Promise<void> => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is good (actual fs)

"extensionDependencies": [
"salesforce.salesforcedx-vscode-services"
"salesforce.salesforcedx-vscode-services",
"salesforce.salesforcedx-vscode-metadata"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it an extension depedendency?

@@ -1,4 +1,5 @@
{
"lightning_generate_lwc_text": "SFDX: Create Lightning Web Component",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

option: if it's easier, bring the LWC template command into this ext and bring its e2e over, too.

You might still want metadata as additionalExtension to retrieve stuff for web, if you decide to go that way.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have been doing that pattern with vf, etc (put the template commands in the ext they go with)

Comment on lines +69 to +70
// Always read `vscode.workspace.workspaceFolders` fresh. Cached workspace info on web poisoned the first
// value when the memo ran before `vscode-test-web` mounted the folder (empty / wrong `fsPath`), breaking
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that real, or downstream effect of the test-web mount fs stuff you're doing?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't faced it outside of the test-web, but it could happen (per claude). So kept it as perf hit didn't seem too bad.

const setProjectOpenedContext = (value: boolean, reason: string) =>
Effect.promise(async () => {
await vscode.commands.executeCommand('setContext', 'sf:project_opened', value);
console.info(`[ProjectService] sf:project_opened=${String(value)} reason=${reason}`);
Copy link
Copy Markdown
Contributor

@mshanemc mshanemc Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect.logInfo so you can get it in console AND so that it goes into the correct span for otel

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.

2 participants