From 8193cffe774a8bf61a59fa9d2f84afec3ca1abe8 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 28 Aug 2023 15:01:10 -0700 Subject: [PATCH] chore: clean up mutator tests (#7434) * chore: work on cleaning up mutator tests * chore: remove need for dragBlockSelector * chore: add helpers to clean up tests * chore: add issue link in TODO * chore: format and add docs for new helpers * Revert "chore: remove need for dragBlockSelector" This reverts commit dfec88a6aa90eecd6429b6f2a878dd7d5a10793f. * chore: fixup connect helper --- core/flyout_base.ts | 1 + tests/browser/test/mutator_test.js | 85 +++++++++++++--------------- tests/browser/test/test_setup.js | 90 ++++++++++++++++++++---------- 3 files changed, 100 insertions(+), 76 deletions(-) diff --git a/core/flyout_base.ts b/core/flyout_base.ts index e9797df4f..a00c95bd8 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -1213,6 +1213,7 @@ export abstract class Flyout extends DeleteArea implements IFlyout { } // Clone the block. + // TODO(#7432): Add a saveIds parameter to `save`. const json = blocks.save(oldBlock) as blocks.State; // Normallly this resizes leading to weird jumps. Save it for terminateDrag. targetWorkspace.setResizesEnabled(false); diff --git a/tests/browser/test/mutator_test.js b/tests/browser/test/mutator_test.js index 4a65a933c..93e698af6 100644 --- a/tests/browser/test/mutator_test.js +++ b/tests/browser/test/mutator_test.js @@ -4,94 +4,85 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * @fileoverview Node.js script to run Automated tests in Chrome, via webdriver. - */ - const chai = require('chai'); const { testSetup, testFileLocations, connect, - switchRTL, dragBlockTypeFromFlyout, - getSelectedBlockId, screenDirection, PAUSE_TIME, + getBlockElementById, + dragBlockFromMutatorFlyout, + openMutatorForBlock, } = require('./test_setup'); -suite('This tests mutating a Blockly block', function (done) { - // Setting timeout to unlimited as the webdriver takes a longer time to run than most mocha test +suite('Mutating a block', function (done) { this.timeout(0); - // Setup Selenium for all of the tests suiteSetup(async function () { this.browser = await testSetup(testFileLocations.PLAYGROUND); }); - test('This test mutating a block creates more inputs', async function () { - await testingMutator(this.browser, screenDirection.LTR); + test('Mutating a block creates more inputs', async function () { + await testMutator(this.browser, screenDirection.LTR); }); }); -async function testingMutator(browser, delta) { - // Drag out print from flyout. - const controlIfFlyout = await dragBlockTypeFromFlyout( +async function testMutator(browser, delta) { + const mutatorBlock = await dragBlockTypeFromFlyout( browser, 'Logic', 'controls_if', delta * 50, 50, ); - // Click on the mutator and drag out else if block - const mutatorWheel = await browser.$( - '#blocklyDiv > div > svg.blocklySvg > g > g.blocklyBlockCanvas > g.blocklyDraggable.blocklySelected > g.blocklyIconGroup', - ); - await mutatorWheel.click(); + await openMutatorForBlock(browser, mutatorBlock); await browser.pause(PAUSE_TIME); - const elseIfFlyout = await browser.$( - '#blocklyDiv > div > svg.blocklySvg > g > g.blocklyBubbleCanvas > g > g:nth-child(2) > svg:nth-child(1) > g > g.blocklyFlyout > g > g.blocklyBlockCanvas > g:nth-child(3)', + await dragBlockFromMutatorFlyout( + browser, + mutatorBlock, + 'controls_if_elseif', + delta * 50, + 50, ); - await elseIfFlyout.dragAndDrop({x: delta * 50, y: 42}); await browser.pause(PAUSE_TIME); - await browser.pause(PAUSE_TIME); - // Get the ids for the blocks in the mutator - const blockIds = await browser.execute(() => { - const mutatorBlock = Blockly.getMainWorkspace().getAllBlocks()[0]; - // Adding the first element in the array is the original block id, the second is the first mutator block, and the third is the second mutator block - const blockIds = [ - mutatorBlock.id, - mutatorBlock.mutator.getWorkspace().getAllBlocks()[0].id, - mutatorBlock.mutator.getWorkspace().getAllBlocks()[1].id, - ]; - return blockIds; - }); + const {mutatorBlockId, ifQuarkId, elseIfQuarkId} = await browser.execute( + () => { + const mutatorBlock = Blockly.getMainWorkspace().getAllBlocks()[0]; + const quarkBlocks = mutatorBlock.mutator.getWorkspace().getAllBlocks(); + return { + mutatorBlockId: mutatorBlock.id, + ifQuarkId: quarkBlocks[0].id, + elseIfQuarkId: quarkBlocks[1].id, + }; + }, + ); - // The flyout block and the workspace block have the same id, so to get around that I pass in the selector to the connect function + // The flyout block and the workspace block have the same id, so to get + // around that I pass in the selector to the connect function. const dragBlockSelector = await browser.$( - '#blocklyDiv > div > svg.blocklySvg > g > g.blocklyBubbleCanvas > g > g:nth-child(2) > svg:nth-child(1) > g > g.blocklyBlockCanvas > g.blocklyDraggable', + '#blocklyDiv > div > svg.blocklySvg > g > g.blocklyBubbleCanvas > g > ' + + 'g:nth-child(2) > svg:nth-child(1) > g > g.blocklyBlockCanvas > ' + + 'g.blocklyDraggable', ); - // For some reason this needs a lot more time + // For some reason this needs a lot more time. await browser.pause(2000); - // Connect the mutator blocks await connect( browser, - blockIds[2], + await getBlockElementById(browser, elseIfQuarkId), 'PREVIOUS', - blockIds[1], + await getBlockElementById(browser, ifQuarkId), 'NEXT', - blockIds[0], + mutatorBlockId, dragBlockSelector, ); await browser.pause(PAUSE_TIME); - // Get the ids for block after mutating - const afterInputs = await browser.execute(() => { - const afterInputs = - Blockly.getMainWorkspace().getAllBlocks()[0].inputList.length; - return afterInputs; + const finalInputCount = await browser.execute(() => { + return Blockly.getMainWorkspace().getAllBlocks()[0].inputList.length; }); - chai.assert.equal(afterInputs, 4); + chai.assert.equal(finalInputCount, 4); } diff --git a/tests/browser/test/test_setup.js b/tests/browser/test/test_setup.js index 9bc660421..69e851b6c 100644 --- a/tests/browser/test/test_setup.js +++ b/tests/browser/test/test_setup.js @@ -295,7 +295,8 @@ async function getLocationOfBlockConnection( * @param draggedConnection The active connection on the block being dragged. * @param targetBlock The block to drag to. * @param targetConnection The connection to connect to on the target block. - * @param mutatorBlockId The block that holds the mutator icon or null if the target block is on the main workspace + * @param mutatorBlockId The block that holds the mutator icon or null if the + * target block is on the main workspace * @param dragBlockSelector The selector of the block to drag * @return A Promise that resolves when the actions are completed. */ @@ -308,34 +309,18 @@ async function connect( mutatorBlockId, dragBlockSelector, ) { - let draggedLocation; - let targetLocation; - - if (mutatorBlockId) { - draggedLocation = await getLocationOfBlockConnection( - browser, - draggedBlock, - draggedConnection, - mutatorBlockId, - ); - targetLocation = await getLocationOfBlockConnection( - browser, - targetBlock, - targetConnection, - mutatorBlockId, - ); - } else { - draggedLocation = await getLocationOfBlockConnection( - browser, - draggedBlock.id, - draggedConnection, - ); - targetLocation = await getLocationOfBlockConnection( - browser, - targetBlock.id, - targetConnection, - ); - } + const draggedLocation = await getLocationOfBlockConnection( + browser, + draggedBlock.id, + draggedConnection, + mutatorBlockId, + ); + const targetLocation = await getLocationOfBlockConnection( + browser, + targetBlock.id, + targetConnection, + mutatorBlockId, + ); const delta = { x: targetLocation.x - draggedLocation.x, @@ -405,6 +390,39 @@ async function dragBlockTypeFromFlyout(browser, categoryName, type, x, y) { return await getSelectedBlockElement(browser); } +/** + * Drags the specified block type from the mutator flyout of the given block and + * returns the root element of the block. + * + * @param browser The active WebdriverIO Browser object. + * @param mutatorBlock The block with the mutator attached that we want to drag + * a block from. + * @param type The type of the block to search for. + * @param x The x-distance to drag, as a delta from the block's + * initial location on screen. + * @param y The y-distance to drag, as a delta from the block's + * initial location on screen. + * @return A Promise that resolves to the root element of the newly + * created block. + */ +async function dragBlockFromMutatorFlyout(browser, mutatorBlock, type, x, y) { + const id = await browser.execute( + (mutatorBlockId, blockType) => { + return Blockly.getMainWorkspace() + .getBlockById(mutatorBlockId) + .mutator.getWorkspace() + .getFlyout() + .getWorkspace() + .getBlocksByType(blockType)[0].id; + }, + mutatorBlock.id, + type, + ); + const flyoutBlock = await getBlockElementById(browser, id); + await flyoutBlock.dragAndDrop({x: x, y: y}); + return await getSelectedBlockElement(browser); +} + /** * Right-click on the specified block, then click on the specified * context menu item. @@ -435,6 +453,18 @@ async function contextMenuSelect(browser, block, itemText) { await browser.pause(PAUSE_TIME); } +/** + * Opens the mutator bubble for the given block. + * + * @param browser The active WebdriverIO Browser object. + * @param block The block to click, as an interactable element. + * @return A Promise that resolves when the actions are complete. + */ +async function openMutatorForBlock(browser, block) { + const icon = await browser.$(`[data-id="${block.id}"] > g.blocklyIconGroup`); + await icon.click(); +} + /** * Get all blocks on the main workspace. Because the blocks have circular * references that can't be JSON-encoded they can't be returned directly, so @@ -490,9 +520,11 @@ module.exports = { getBlockTypeFromCategory, dragNthBlockFromFlyout, dragBlockTypeFromFlyout, + dragBlockFromMutatorFlyout, connect, switchRTL, contextMenuSelect, + openMutatorForBlock, screenDirection, getBlockTypeFromWorkspace, getAllBlocks,