diff --git a/test/webdriverio/test/actions_test.ts b/test/webdriverio/test/actions_test.ts index be5a3ca7..2cd55f2e 100644 --- a/test/webdriverio/test/actions_test.ts +++ b/test/webdriverio/test/actions_test.ts @@ -15,6 +15,8 @@ import { testFileLocations, testSetup, keyRight, + sendKeyAndWait, + getCurrentFocusedBlockId, } from './test_setup.js'; suite('Menus test', function () { @@ -31,9 +33,7 @@ suite('Menus test', function () { // Navigate to draw_circle_1. await tabNavigateToWorkspace(this.browser); await focusOnBlock(this.browser, 'draw_circle_1'); - await this.browser.pause(PAUSE_TIME); - await this.browser.keys([Key.Ctrl, Key.Return]); - await this.browser.pause(PAUSE_TIME); + await sendKeyAndWait(this.browser, [Key.Ctrl, Key.Return]); chai.assert.isTrue( await contextMenuExists(this.browser, 'Collapse Block'), 'The menu should be openable on a block', @@ -48,8 +48,7 @@ suite('Menus test', function () { await moveToToolboxCategory(this.browser, 'Functions'); // Move to flyout. await keyRight(this.browser); - await this.browser.keys([Key.Ctrl, Key.Return]); - await this.browser.pause(PAUSE_TIME); + await sendKeyAndWait(this.browser, [Key.Ctrl, Key.Return]); chai.assert.isTrue( await contextMenuExists(this.browser, 'Help'), @@ -62,12 +61,28 @@ suite('Menus test', function () { await tabNavigateToWorkspace(this.browser); await focusOnBlock(this.browser, 'draw_circle_1'); // Start moving the block - await this.browser.keys('m'); - await this.browser.keys([Key.Ctrl, Key.Return]); - await this.browser.pause(PAUSE_TIME); + await sendKeyAndWait(this.browser, 'm'); + await sendKeyAndWait(this.browser, [Key.Ctrl, Key.Return]); chai.assert.isTrue( await contextMenuExists(this.browser, 'Collapse Block', true), 'The menu should not be openable during a move', ); }); + + test('Closing menu restores focus to starting node', async function () { + // Navigate to draw_circle_1. + await tabNavigateToWorkspace(this.browser); + await focusOnBlock(this.browser, 'draw_circle_1'); + // Open the context menu. + await sendKeyAndWait(this.browser, [Key.Ctrl, Key.Return]); + + // Close the context menu. + await sendKeyAndWait(this.browser, Key.Escape); + + // The previously focused now should now again be focused. + chai.assert.strictEqual( + await getCurrentFocusedBlockId(this.browser), + 'draw_circle_1', + ); + }); }); diff --git a/test/webdriverio/test/basic_test.ts b/test/webdriverio/test/basic_test.ts index abfd7dde..04aba7a2 100644 --- a/test/webdriverio/test/basic_test.ts +++ b/test/webdriverio/test/basic_test.ts @@ -21,6 +21,8 @@ import { keyRight, keyUp, keyDown, + sendKeyAndWait, + isEphemeralFocusActive, } from './test_setup.js'; import {Key} from 'webdriverio'; @@ -239,13 +241,11 @@ suite('Keyboard navigation on Blocks', function () { await tabNavigateToWorkspace(this.browser); await this.browser.pause(PAUSE_TIME); await focusOnBlock(this.browser, 'text_print_1'); - await this.browser.keys('m'); - await this.browser.pause(PAUSE_TIME); + await sendKeyAndWait(this.browser, 'm'); chai.assert.isTrue(await isDragging(this.browser)); - await this.browser.keys(Key.Tab); - await this.browser.pause(PAUSE_TIME); + await sendKeyAndWait(this.browser, Key.Tab); chai.assert.isFalse(await isDragging(this.browser)); }); @@ -354,8 +354,7 @@ suite('Keyboard navigation on Fields', function () { // Open a field editor dropdown await focusOnBlockField(this.browser, 'logic_boolean_1', 'BOOL'); await this.browser.pause(PAUSE_TIME); - await this.browser.keys(Key.Enter); - await this.browser.pause(PAUSE_TIME); + await sendKeyAndWait(this.browser, Key.Enter); // Try to navigate to a different block await keyRight(this.browser); @@ -368,13 +367,12 @@ suite('Keyboard navigation on Fields', function () { // Open colour picker await focusOnBlockField(this.browser, 'colour_picker_1', 'COLOUR'); await this.browser.pause(PAUSE_TIME); - await this.browser.keys(Key.Enter); - await this.browser.pause(PAUSE_TIME); + await sendKeyAndWait(this.browser, Key.Enter); // Move right to pick a new colour. await keyRight(this.browser); // Enter to choose. - await this.browser.keys(Key.Enter); + await sendKeyAndWait(this.browser, Key.Enter); // Focus seems to take longer than a single pause to settle. await this.browser.waitUntil( @@ -385,4 +383,38 @@ suite('Keyboard navigation on Fields', function () { {timeout: 1000}, ); }); + + test('Exiting inline field editor should restore focus to field', async function () { + // Select a block with an inline-editable field. + await focusOnBlock(this.browser, 'p5_canvas_1'); + // Select the field. + await keyRight(this.browser); + // Open the field's editor. + await sendKeyAndWait(this.browser, Key.Enter); + + // Exit the editor. + await sendKeyAndWait(this.browser, Key.Escape); + + // The field should be focused without ephemeral focus. + chai.assert.equal(await getFocusedFieldName(this.browser), 'WIDTH'); + chai.assert.isFalse(await isEphemeralFocusActive(this.browser)); + }); + + test('Exiting drop-down field editor should restore focus to field', async function () { + // Select a block with a drop-down editable field. + await focusOnBlock(this.browser, 'logic_boolean_1'); + // Select the field. + await keyRight(this.browser); + // Open the field's editor and select the first option to give a child of + // the editor focus. + await sendKeyAndWait(this.browser, Key.Enter); + await keyDown(this.browser); + + // Exit the editor. + await sendKeyAndWait(this.browser, Key.Escape); + + // The field should be focused without ephemeral focus. + chai.assert.equal(await getFocusedFieldName(this.browser), 'BOOL'); + chai.assert.isFalse(await isEphemeralFocusActive(this.browser)); + }); }); diff --git a/test/webdriverio/test/test_setup.ts b/test/webdriverio/test/test_setup.ts index 213f0bf5..da78aded 100644 --- a/test/webdriverio/test/test_setup.ts +++ b/test/webdriverio/test/test_setup.ts @@ -398,8 +398,9 @@ export async function getFocusedFieldName( browser: WebdriverIO.Browser, ): Promise { return await browser.execute(() => { - const field = Blockly.getFocusManager().getFocusedNode() as Blockly.Field; - return field.name; + const field = + Blockly.getFocusManager().getFocusedNode() as Blockly.Field | null; + return field?.name; }); } @@ -550,6 +551,19 @@ export async function isDragging( }); } +/** + * Returns whether Blockly's FocusManager currently holds ephemeral focus. + * + * @param browser The active WebdriverIO Browser object. + */ +export async function isEphemeralFocusActive( + browser: WebdriverIO.Browser, +): Promise { + return await browser.execute(() => + Blockly.getFocusManager().ephemeralFocusTaken(), + ); +} + /** * Returns the result of the specificied action precondition. *