diff --git a/test/loadTestBlocks.js b/test/loadTestBlocks.js index 14b1269e..3f5c56be 100644 --- a/test/loadTestBlocks.js +++ b/test/loadTestBlocks.js @@ -317,12 +317,12 @@ const moreBlocks = { 'next': { 'block': { 'type': 'text_print', - 'id': 'J`*)bq?#`_Vq^X(DQF2t', + 'id': 'text_print_1', 'inputs': { 'TEXT': { 'shadow': { 'type': 'text', - 'id': '6fW_sIt1t|63j}nPE1ge', + 'id': 'text_print_shadow_text_1', 'fields': { 'TEXT': 'abc', }, diff --git a/test/webdriverio/test/actions_test.ts b/test/webdriverio/test/actions_test.ts index 6b0a86c6..61d47401 100644 --- a/test/webdriverio/test/actions_test.ts +++ b/test/webdriverio/test/actions_test.ts @@ -7,10 +7,13 @@ import * as chai from 'chai'; import {Key} from 'webdriverio'; import { + clickBlock, contextMenuExists, moveToToolboxCategory, PAUSE_TIME, focusOnBlock, + focusWorkspace, + rightClickOnFlyoutBlockType, tabNavigateToWorkspace, testFileLocations, testSetup, @@ -19,6 +22,70 @@ import { contextMenuItems, } from './test_setup.js'; +const isDarwin = process.platform === 'darwin'; + +const blockActionsViaKeyboard = [ + {'text': 'Duplicate D'}, + {'text': 'Add Comment'}, + {'text': 'External Inputs'}, + {'text': 'Collapse Block'}, + {'text': 'Disable Block'}, + {'text': 'Delete 2 Blocks Delete'}, + {'text': 'Move Block M'}, + {'text': 'Edit Block contents Right'}, + {'text': isDarwin ? 'Cut ⌘ X' : 'Cut Ctrl + X'}, + {'text': isDarwin ? 'Copy ⌘ C' : 'Copy Ctrl + C'}, + {'disabled': true, 'text': isDarwin ? 'Paste ⌘ V' : 'Paste Ctrl + V'}, +]; + +const blockActionsViaMouse = [ + {'text': 'Duplicate D'}, + {'text': 'Add Comment'}, + {'text': 'External Inputs'}, + {'text': 'Collapse Block'}, + {'text': 'Disable Block'}, + {'text': 'Delete 2 Blocks Delete'}, + {'text': isDarwin ? 'Cut ⌘ X' : 'Cut Ctrl + X'}, + {'text': isDarwin ? 'Copy ⌘ C' : 'Copy Ctrl + C'}, + {'disabled': true, 'text': isDarwin ? 'Paste ⌘ V' : 'Paste Ctrl + V'}, +]; + +const shadowBlockActionsViaKeyboard = [ + {'text': 'Add Comment'}, + {'text': 'Collapse Block'}, + {'text': 'Disable Block'}, + {'text': 'Help'}, + {'text': 'Move Block M'}, + {'text': 'Edit Block contents Right'}, + {'disabled': true, 'text': isDarwin ? 'Cut ⌘ X' : 'Cut Ctrl + X'}, + {'text': isDarwin ? 'Copy ⌘ C' : 'Copy Ctrl + C'}, + {'disabled': true, 'text': isDarwin ? 'Paste ⌘ V' : 'Paste Ctrl + V'}, +]; + +const toolboxBlockActionsViaKeyboard = [ + {'text': 'Help'}, + {'disabled': true, 'text': 'Move Block M'}, + {'disabled': true, 'text': isDarwin ? 'Cut ⌘ X' : 'Cut Ctrl + X'}, + {'text': isDarwin ? 'Copy ⌘ C' : 'Copy Ctrl + C'}, +]; + +const flyoutBlockActionsViaMouse = [ + {'text': 'Help'}, + {'disabled': true, 'text': isDarwin ? 'Cut ⌘ X' : 'Cut Ctrl + X'}, + {'text': isDarwin ? 'Copy ⌘ C' : 'Copy Ctrl + C'}, +]; + +const workspaceActionsViaKeyboard = [ + {'disabled': true, 'text': 'Undo'}, + {'disabled': true, 'text': 'Redo'}, + {'text': 'Clean up Blocks'}, + {'text': 'Collapse Blocks'}, + {'disabled': true, 'text': 'Expand Blocks'}, + {'text': 'Delete 14 Blocks'}, + {'text': 'Add Comment'}, + {'disabled': true, 'text': isDarwin ? 'Paste ⌘ V' : 'Paste Ctrl + V'}, +]; + suite('Menus test', function () { // Disable timeouts when non-zero PAUSE_TIME is used to watch tests run. if (PAUSE_TIME) this.timeout(0); @@ -30,51 +97,47 @@ suite('Menus test', function () { // seconds. Allow 30s just in case. this.timeout(30000); - this.browser = await testSetup(testFileLocations.BASE); + this.browser = await testSetup(testFileLocations.MORE_BLOCKS); await this.browser.pause(PAUSE_TIME); }); - test('Menu on block', async function () { + test('Menu action via keyboard on block opens menu', async function () { // Navigate to draw_circle_1. await focusOnBlock(this.browser, 'draw_circle_1'); await this.browser.pause(PAUSE_TIME); await sendKeyAndWait(this.browser, [Key.Ctrl, Key.Return]); chai.assert.deepEqual( - process.platform === 'darwin' - ? [ - {'text': 'Duplicate D'}, - {'text': 'Add Comment'}, - {'text': 'External Inputs'}, - {'text': 'Collapse Block'}, - {'text': 'Disable Block'}, - {'text': 'Delete 2 Blocks Delete'}, - {'text': 'Move Block M'}, - {'text': 'Edit Block contents Right'}, - {'text': 'Cut ⌘ X'}, - {'text': 'Copy ⌘ C'}, - {'disabled': true, 'text': 'Paste ⌘ V'}, - ] - : [ - {'text': 'Duplicate D'}, - {'text': 'Add Comment'}, - {'text': 'External Inputs'}, - {'text': 'Collapse Block'}, - {'text': 'Disable Block'}, - {'text': 'Delete 2 Blocks Delete'}, - {'text': 'Move Block M'}, - {'text': 'Edit Block contents Right'}, - {'text': 'Cut Ctrl + X'}, - {'text': 'Copy Ctrl + C'}, - {'disabled': true, 'text': 'Paste Ctrl + V'}, - ], await contextMenuItems(this.browser), + blockActionsViaKeyboard, ); }); - test('Menu on block in the toolbox', async function () { - // Navigate to draw_circle_1. - await focusOnBlock(this.browser, 'draw_circle_1'); + test('Block menu via mouse displays expected items', async function () { + await tabNavigateToWorkspace(this.browser); + await clickBlock(this.browser, 'draw_circle_1', {button: 'right'}); + + chai.assert.deepEqual( + await contextMenuItems(this.browser), + blockActionsViaMouse, + ); + }); + + test('Shadow block menu via keyboard displays expected items', async function () { + await tabNavigateToWorkspace(this.browser); + await focusOnBlock(this.browser, 'text_print_1'); + await this.browser.keys(Key.ArrowRight); + await this.browser.keys([Key.Ctrl, Key.Return]); + await this.browser.pause(PAUSE_TIME); + + chai.assert.deepEqual( + await contextMenuItems(this.browser), + shadowBlockActionsViaKeyboard, + ); + }); + + test('Menu action on block in the toolbox', async function () { + await tabNavigateToWorkspace(this.browser); // Navigate to a toolbox category await moveToToolboxCategory(this.browser, 'Functions'); // Move to flyout. @@ -82,20 +145,24 @@ suite('Menus test', function () { await sendKeyAndWait(this.browser, [Key.Ctrl, Key.Return]); chai.assert.deepEqual( - process.platform === 'darwin' - ? [ - {'text': 'Help'}, - {'disabled': true, 'text': 'Move Block M'}, - {'disabled': true, 'text': 'Cut ⌘ X'}, - {'text': 'Copy ⌘ C'}, - ] - : [ - {'text': 'Help'}, - {'disabled': true, 'text': 'Move Block M'}, - {'disabled': true, 'text': 'Cut Ctrl + X'}, - {'text': 'Copy Ctrl + C'}, - ], await contextMenuItems(this.browser), + toolboxBlockActionsViaKeyboard, + ); + }); + + test('Flyout block menu via mouse displays expected items', async function () { + await tabNavigateToWorkspace(this.browser); + // Navigate to a toolbox category + await moveToToolboxCategory(this.browser, 'Math'); + // Move to flyout. + await keyRight(this.browser); + await this.browser.pause(PAUSE_TIME); + await rightClickOnFlyoutBlockType(this.browser, 'math_number'); + await this.browser.pause(PAUSE_TIME); + + chai.assert.deepEqual( + await contextMenuItems(this.browser), + flyoutBlockActionsViaMouse, ); }); @@ -106,28 +173,8 @@ suite('Menus test', function () { await sendKeyAndWait(this.browser, [Key.Ctrl, Key.Return]); chai.assert.deepEqual( - process.platform === 'darwin' - ? [ - {'disabled': true, 'text': 'Undo'}, - {'disabled': true, 'text': 'Redo'}, - {'text': 'Clean up Blocks'}, - {'text': 'Collapse Blocks'}, - {'disabled': true, 'text': 'Expand Blocks'}, - {'text': 'Delete 4 Blocks'}, - {'text': 'Add Comment'}, - {'disabled': true, 'text': 'Paste ⌘ V'}, - ] - : [ - {'disabled': true, 'text': 'Undo'}, - {'disabled': true, 'text': 'Redo'}, - {'text': 'Clean up Blocks'}, - {'text': 'Collapse Blocks'}, - {'disabled': true, 'text': 'Expand Blocks'}, - {'text': 'Delete 4 Blocks'}, - {'text': 'Add Comment'}, - {'disabled': true, 'text': 'Paste Ctrl + V'}, - ], await contextMenuItems(this.browser), + workspaceActionsViaKeyboard, ); }); @@ -143,4 +190,32 @@ suite('Menus test', function () { 'The menu should not be openable during a move', ); }); + + test('Escape key dismisses menu', async function () { + 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 this.browser.keys(Key.Escape); + await this.browser.pause(PAUSE_TIME); + + chai.assert.isTrue( + await contextMenuExists(this.browser, 'Duplicate', /* reverse= */ true), + 'The menu should be closed', + ); + }); + + test('Clicking workspace dismisses menu', async function () { + await tabNavigateToWorkspace(this.browser); + await clickBlock(this.browser, 'draw_circle_1', {button: 'right'}); + await this.browser.pause(PAUSE_TIME); + await focusWorkspace(this.browser); + await this.browser.pause(PAUSE_TIME); + + chai.assert.isTrue( + await contextMenuExists(this.browser, 'Duplicate', /* reverse= */ true), + 'The menu should be closed', + ); + }); }); diff --git a/test/webdriverio/test/test_setup.ts b/test/webdriverio/test/test_setup.ts index ccba37c1..4d77fbcb 100644 --- a/test/webdriverio/test/test_setup.ts +++ b/test/webdriverio/test/test_setup.ts @@ -153,6 +153,8 @@ export const testFileLocations = { new URLSearchParams({scenario: 'navigationTestBlocks'}), ), // eslint-disable-next-line @typescript-eslint/naming-convention + MORE_BLOCKS: createTestUrl(new URLSearchParams({scenario: 'moreBlocks'})), + // eslint-disable-next-line @typescript-eslint/naming-convention MOVE_TEST_BLOCKS: createTestUrl( new URLSearchParams({scenario: 'moveTestBlocks'}), ), @@ -188,7 +190,7 @@ export async function focusWorkspace(browser: WebdriverIO.Browser) { const workspaceElement = await browser.$( '#blocklyDiv > div > svg.blocklySvg > g', ); - await workspaceElement.click(); + await workspaceElement.click({x: 100}); } /** @@ -573,7 +575,7 @@ export async function isDragging( } /** - * Returns the result of the specificied action precondition. + * Returns the result of the specified action precondition. * * @param browser The active WebdriverIO Browser object. * @param action The action to check the precondition for. @@ -710,3 +712,17 @@ export async function clickBlock( document.getElementById(elemId)?.removeAttribute('id'); }, findableId); } + +/** + * Right-clicks on a block with the provided type in the flyout. + * + * @param browser The active WebdriverIO Browser object. + * @param blockType The name of the type block to right click on. + */ +export async function rightClickOnFlyoutBlockType( + browser: WebdriverIO.Browser, + blockType: string, +) { + const elem = await browser.$(`.blocklyFlyout .${blockType}`); + await elem.click({button: 'right'}); +}