From d13245168d979f2403522d359f43edeb41ab9de4 Mon Sep 17 00:00:00 2001 From: Matthias Rolke Date: Thu, 5 Dec 2024 22:20:12 +0100 Subject: [PATCH] feat: use the new setup domain for lightning pages if available Opening a `/lightning/` setup page on the instance domain caused multiple server- and client-side redirects to the new setup domain. This caused errors like: > failed: Protocol error (DOM.describeNode): Cannot find context with specified id Now all lightning pages should open using the new setup domain if available and use the instance URL otherwise. Example: https://[MyDomainName].my.salesforce-setup.com --- src/browserforce.ts | 21 ++++++++++++++++++++- src/pages/login.ts | 6 +++--- test/browserforce.e2e-spec.ts | 4 +--- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/browserforce.ts b/src/browserforce.ts index 49726313..230fff46 100644 --- a/src/browserforce.ts +++ b/src/browserforce.ts @@ -13,6 +13,8 @@ export class Browserforce { public logger?: Ux; public browser: Browser; public page: Page; + public lightningSetupUrl: string; + constructor(org: Org, logger?: Ux) { this.org = org; this.logger = logger; @@ -62,7 +64,8 @@ export class Browserforce { const result = await pRetry( async () => { page = await this.getNewPage(); - const url = `${this.getInstanceUrl()}/${urlPath}`; + const setupUrl = urlPath.startsWith("lightning") ? await this.getLightningSetupUrl() : this.getInstanceUrl(); + const url = `${setupUrl}/${urlPath}`; const response = await page.goto(url, options); if (response) { if (!response.ok()) { @@ -124,6 +127,22 @@ export class Browserforce { // sometimes the instanceUrl includes a trailing slash return this.org.getConnection().instanceUrl?.replace(/\/$/, ''); } + + /** + * @returns the setup url (e.g. https://[MyDomainName].my.salesforce-setup.com) + */ + public async getLightningSetupUrl(): Promise { + if (!this.lightningSetupUrl) { + const page = await this.getNewPage(); + try { + const lightningResponse = await page.goto(`${this.getInstanceUrl()}/lightning/setup/SetupOneHome/home`, {waitUntil: ["load", "networkidle2"]}); + this.lightningSetupUrl = new URL(lightningResponse.url()).origin; + } finally { + await page.close(); + } + } + return this.lightningSetupUrl; + } } export async function throwPageErrors(page: Page): Promise { diff --git a/src/pages/login.ts b/src/pages/login.ts index d3f64ce9..16992ac1 100644 --- a/src/pages/login.ts +++ b/src/pages/login.ts @@ -19,14 +19,14 @@ export class LoginPage { throw new Error('login failed'); } const conn = org.getConnection(); - await this.page.goto( - `${conn.instanceUrl}/${PATH}?sid=${conn.accessToken}&retURL=${encodeURIComponent(POST_LOGIN_PATH)}`, + const response = await this.page.goto( + `${conn.instanceUrl.replace(/\/$/, '')}/${PATH}?sid=${conn.accessToken}&retURL=${encodeURIComponent(POST_LOGIN_PATH)}`, { // should have waited at least 500ms for network connections, redirects should probably have happened already waitUntil: ['load', 'networkidle2'] } ); - const url = new URL(this.page.url()); + const url = new URL(response.url()); if (url.searchParams.has('startURL')) { // when query param startURL exists, the login failed // e.g. /?ec=302&startURL=https... diff --git a/test/browserforce.e2e-spec.ts b/test/browserforce.e2e-spec.ts index 8d450428..eec54828 100644 --- a/test/browserforce.e2e-spec.ts +++ b/test/browserforce.e2e-spec.ts @@ -33,9 +33,7 @@ describe('Browserforce', function () { }); describe('waitForSelectorInFrameOrPage()', () => { it('should query a selector in LEX and Classic UI', async () => { - const page = await global.bf.openPage('lightning/setup/ExternalStrings/home', { - waitUntil: ['load', 'networkidle2'] - }); + const page = await global.bf.openPage('lightning/setup/ExternalStrings/home'); const frame = await global.bf.waitForSelectorInFrameOrPage(page, 'input[name="edit"]'); const button = await frame.$('input[name="edit"]'); assert.ok(!page.url().includes('/page'));