feat(lwc): add LWC LSP Playwright E2E test suite with web + desktop coverage W-22187438#7248
feat(lwc): add LWC LSP Playwright E2E test suite with web + desktop coverage W-22187438#7248
Conversation
…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
|
|
||
| 1. Branch: `feature/my-branch` | ||
| 2. Find "Metadata E2E (Playwright)" `in_progress` | ||
| 2. Find "Metadata E2E (Playwright)" or "LWC E2E (Playwright)" `in_progress` |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
I think I had problems with this in the past, but if it works fine locally now that's great.
There was a problem hiding this comment.
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> => { |
There was a problem hiding this comment.
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 */ |
There was a problem hiding this comment.
see https://github.com/Leonidas-from-XIV/node-xml2js#options
explicitArray
There was a problem hiding this comment.
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'); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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') { |
There was a problem hiding this comment.
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> => { |
There was a problem hiding this comment.
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> => { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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` |
There was a problem hiding this comment.
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> => { |
There was a problem hiding this comment.
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> => { |
| "extensionDependencies": [ | ||
| "salesforce.salesforcedx-vscode-services" | ||
| "salesforce.salesforcedx-vscode-services", | ||
| "salesforce.salesforcedx-vscode-metadata" |
There was a problem hiding this comment.
why is it an extension depedendency?
| @@ -1,4 +1,5 @@ | |||
| { | |||
| "lightning_generate_lwc_text": "SFDX: Create Lightning Web Component", | |||
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
have been doing that pattern with vf, etc (put the template commands in the ext they go with)
| // 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 |
There was a problem hiding this comment.
is that real, or downstream effect of the test-web mount fs stuff you're doing?
There was a problem hiding this comment.
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}`); |
There was a problem hiding this comment.
Effect.logInfo so you can get it in console AND so that it goes into the correct span for otel
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:
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>