diff --git a/test/source/browser/controllable.ts b/test/source/browser/controllable.ts index a663f62d5b2..e7e5b35f615 100644 --- a/test/source/browser/controllable.ts +++ b/test/source/browser/controllable.ts @@ -536,6 +536,10 @@ abstract class ControllableBase { return files; }; + public keyboard = () => { + return 'keyboard' in this.target ? this.target.keyboard : this.target.page().keyboard; + }; + protected log = (msg: string) => { if (this.debugNamespace) { console.info(`[debug][controllable][${this.debugNamespace}] ${msg}`); diff --git a/test/source/mock/google/google-endpoints.ts b/test/source/mock/google/google-endpoints.ts index 935cf9c8cbd..580989e184f 100644 --- a/test/source/mock/google/google-endpoints.ts +++ b/test/source/mock/google/google-endpoints.ts @@ -221,7 +221,11 @@ export const mockGoogleEndpoints: HandlersDefinition = { // get msg or attachment const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); if (isGet(req)) { - const id = parseResourceId(req.url!); // eslint-disable-line @typescript-eslint/no-non-null-assertion + // temporary replacement for parseResourceId() until #5050 is fixed + const id = req.url!.match(/\/([a-zA-Z0-9\-_]+)(\?|$)/)?.[1]; // eslint-disable-line @typescript-eslint/no-non-null-assertion + if (!id) { + return {}; + } const data = await GoogleData.withInitializedData(acct); if (req.url?.includes('/attachments/')) { const attachment = data.getAttachment(id); diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index 7e8bad3f292..7b905a6f5b8 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -2661,8 +2661,10 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te const settingsPage = await BrowserRecipe.openSettingsLoginApprove(t, browser, acct); await SetupPageRecipe.autoSetupWithEKM(settingsPage); const composePage = await ComposePageRecipe.openStandalone(t, browser, acct); - await ComposePageRecipe.fillMsg(composePage, { to: 'mock.only.pubkey@flowcrypt.com' }, 'no valid key'); - await ComposePageRecipe.waitForToastToAppearAndDisappear(composePage, 'Draft not saved: Error: Your account keys are revoked'); + await Promise.all([ + ComposePageRecipe.fillMsg(composePage, { to: 'mock.only.pubkey@flowcrypt.com' }, 'no valid key'), + ComposePageRecipe.waitForToastToAppearAndDisappear(composePage, 'Draft not saved: Error: Your account keys are revoked'), + ]); await composePage.waitAndClick('@action-send', { delay: 1 }); await PageRecipe.waitForModalAndRespond(composePage, 'warning', { contentToCheck: 'Failed to send message due to: Error: Your account keys are revoked', diff --git a/test/source/tests/page-recipe/compose-page-recipe.ts b/test/source/tests/page-recipe/compose-page-recipe.ts index d894995f915..2d56363b7bd 100644 --- a/test/source/tests/page-recipe/compose-page-recipe.ts +++ b/test/source/tests/page-recipe/compose-page-recipe.ts @@ -78,22 +78,28 @@ export class ComposePageRecipe extends PageRecipe { body?: string | undefined, sendingOpt: { encrypt?: boolean; sign?: boolean; richtext?: boolean } = {} // undefined means leave default ) { - await Util.sleep(0.5); - await ComposePageRecipe.fillRecipients(composePageOrFrame, recipients); - if (subject) { - await composePageOrFrame.click('@input-subject'); - await Util.sleep(1); - await composePageOrFrame.type('@input-subject', subject?.match(/RTL/) ? subject : `Automated puppeteer test: ${subject}`); - } const sendingOpts = sendingOpt as { [key: string]: boolean | undefined }; const keys = ['richtext', 'encrypt', 'sign']; - await composePageOrFrame.type('@input-body', body || subject || ''); // fall back to subject if body is not provided for (const opt of keys) { const shouldBeTicked = sendingOpts[opt]; if (typeof shouldBeTicked !== 'undefined') { await ComposePageRecipe.setPopoverToggle(composePageOrFrame, opt as PopoverOpt, shouldBeTicked); } } + await Util.sleep(0.5); // todo: should we wait only if we didn't modify any sendingOpts? + await ComposePageRecipe.fillRecipients(composePageOrFrame, recipients); + if (subject) { + await composePageOrFrame.click('@input-subject'); + await Util.sleep(1); + await composePageOrFrame.type('@input-subject', subject?.match(/RTL/) ? subject : `Automated puppeteer test: ${subject}`); + } + await composePageOrFrame.click('@input-body'); + // bring cursor to the beginning of the multiline contenteditable + const keyboard = composePageOrFrame.keyboard(); + await keyboard.down('Control'); + await keyboard.press('Home'); + await keyboard.up('Control'); + await composePageOrFrame.type('@input-body', body || subject || ''); // fall back to subject if body is not provided return { subject, body }; }