From 07ba841850f1db4c49e088b46a40a9d0f717b1e3 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 6 Jul 2023 15:35:58 -0700 Subject: [PATCH] chore: add test helpers for connecting blocks (#7258) * chore: get procedure test passing on linux * chore: cleanup * chore: format --- core/rendered_connection.ts | 1 - core/utils/svg_math.ts | 28 ++++++++++ tests/browser/test/procedure_test.js | 41 ++++++-------- tests/browser/test/test_setup.js | 82 +++++++++++++++++++++++++--- 4 files changed, 121 insertions(+), 31 deletions(-) diff --git a/core/rendered_connection.ts b/core/rendered_connection.ts index c1e01f86c..a3cd51a96 100644 --- a/core/rendered_connection.ts +++ b/core/rendered_connection.ts @@ -262,7 +262,6 @@ export class RenderedConnection extends Connection { * Get the offset of this connection relative to the top left of its block. * * @returns The offset of the connection. - * @internal */ getOffsetInBlock(): Coordinate { return this.offsetInBlock; diff --git a/core/utils/svg_math.ts b/core/utils/svg_math.ts index 4c583a49f..1eef15db5 100644 --- a/core/utils/svg_math.ts +++ b/core/utils/svg_math.ts @@ -175,6 +175,34 @@ export function screenToWsCoordinates( return finalOffsetMainWs; } +/** + * Converts workspace coordinates to screen coordinates. + * + * @param ws The workspace to get the coordinates out of. + * @param workspaceCoordinates The workspace coordinates to be converted + * to screen coordinates. + * @returns The screen coordinates. + */ +export function wsToScreenCoordinates( + ws: WorkspaceSvg, + workspaceCoordinates: Coordinate +): Coordinate { + // Fix workspace scale vs browser scale. + const screenCoordinates = workspaceCoordinates.scale(ws.scale); + const screenX = screenCoordinates.x; + const screenY = screenCoordinates.y; + + const injectionDiv = ws.getInjectionDiv(); + const boundingRect = injectionDiv.getBoundingClientRect(); + const mainOffset = ws.getOriginOffsetInPixels(); + + // Fix workspace origin vs browser origin. + return new Coordinate( + screenX + boundingRect.left + mainOffset.x, + screenY + boundingRect.top + mainOffset.y + ); +} + export const TEST_ONLY = { XY_REGEX, XY_STYLE_REGEX, diff --git a/tests/browser/test/procedure_test.js b/tests/browser/test/procedure_test.js index 69e66c7c1..2a32bf8e1 100644 --- a/tests/browser/test/procedure_test.js +++ b/tests/browser/test/procedure_test.js @@ -15,6 +15,7 @@ const { getSelectedBlockElement, getNthBlockOfCategory, getBlockTypeFromCategory, + connect, } = require('./test_setup'); let browser; @@ -37,6 +38,7 @@ suite('Testing Connecting Blocks', function (done) { ); await proceduresDefReturn.dragAndDrop({x: 50, y: 20}); await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec + const doSomething = await getSelectedBlockElement(browser); // Drag out second function. proceduresDefReturn = await getBlockTypeFromCategory( @@ -46,6 +48,7 @@ suite('Testing Connecting Blocks', function (done) { ); await proceduresDefReturn.dragAndDrop({x: 300, y: 200}); await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec + const doSomething2 = await getSelectedBlockElement(browser); // Drag out numeric const mathNumeric = await getBlockTypeFromCategory( @@ -55,32 +58,25 @@ suite('Testing Connecting Blocks', function (done) { ); await mathNumeric.dragAndDrop({x: 50, y: 20}); await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec + const numeric = await getSelectedBlockElement(browser); // Connect numeric to first procedure - const numericWorkspace = await getSelectedBlockElement(browser); - const doSomething = await browser.$( - '#content_blocks > div > svg.blocklySvg > g > g.blocklyBlockCanvas > g:nth-child(2)' - ); - await numericWorkspace.dragAndDrop(doSomething); - await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec - await numericWorkspace.dragAndDrop({x: 100, y: 25}); - await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec + await connect(browser, numeric, 'OUTPUT', doSomething, 'RETURN'); - // Drag out doSomething from flyout and connect it to doSomething2 - const doSomething2 = await browser.$( - '#content_blocks > div > svg.blocklySvg > g > g.blocklyBlockCanvas > g:nth-child(2)' - ); + // Drag out doSomething caller from flyout. const doSomethingFlyout = await getNthBlockOfCategory( browser, 'Functions', 3 ); - await doSomethingFlyout.dragAndDrop(doSomething2); + await doSomethingFlyout.dragAndDrop({x: 50, y: 20}); await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec - const doSomethingFlyoutWorkspace = await getSelectedBlockElement(browser); - await doSomethingFlyoutWorkspace.dragAndDrop({x: 130, y: 20}); + const doSomethingCaller = await getSelectedBlockElement(browser); - // Drag out print from flyout and connect it with doSomething 2 + // Connect the doSomething caller to doSomething2 + await connect(browser, doSomethingCaller, 'OUTPUT', doSomething2, 'RETURN'); + + // Drag out print from flyout. const printFlyout = await getBlockTypeFromCategory( browser, 'Text', @@ -88,6 +84,9 @@ suite('Testing Connecting Blocks', function (done) { ); await printFlyout.dragAndDrop({x: 50, y: 20}); await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec + const print = await getSelectedBlockElement(browser); + + // Drag out doSomething2 caller from flyout. const doSomething2Flyout = await getNthBlockOfCategory( browser, 'Functions', @@ -96,14 +95,10 @@ suite('Testing Connecting Blocks', function (done) { await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec await doSomething2Flyout.dragAndDrop({x: 130, y: 20}); await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec - const doSomething2FlyoutWorkspace = await getSelectedBlockElement(browser); + const doSomething2Caller = await getSelectedBlockElement(browser); - const printWorkSpace = await browser.$( - '#content_blocks > div > svg.blocklySvg > g > g.blocklyBlockCanvas > g:nth-child(4)' - ); - await doSomething2FlyoutWorkspace.dragAndDrop(printWorkSpace); - await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec - await doSomething2FlyoutWorkspace.dragAndDrop({x: 65, y: 0}); + // Connect doSomething2 caller with print. + await connect(browser, doSomething2Caller, 'OUTPUT', print, 'TEXT'); // Click run button and verify the number is 123 await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec diff --git a/tests/browser/test/test_setup.js b/tests/browser/test/test_setup.js index 819ae7d92..7d8d04861 100644 --- a/tests/browser/test/test_setup.js +++ b/tests/browser/test/test_setup.js @@ -73,17 +73,21 @@ const testFileLocations = { playground: 2, }; +async function getSelectedBlockId(browser) { + return await browser.execute(() => { + // Note: selected is an ICopyable and I am assuming that it is a BlockSvg. + return Blockly.common.getSelected()?.id; + }); +} + /** * @param {Browser} browser The active WebdriverIO Browser object. * @return {WebElement} The selected block's root SVG element, as an interactable * browser element. */ async function getSelectedBlockElement(browser) { - const result = await browser.execute(() => { - // Note: selected is an ICopyable and I am assuming that it is a BlockSvg. - return Blockly.common.getSelected()?.id; - }); - return await browser.$(`[data-id="${result}"]`); + const id = await getSelectedBlockId(browser); + return getBlockElementById(browser, id); } /** @@ -93,7 +97,9 @@ async function getSelectedBlockElement(browser) { * interactable browser element. */ async function getBlockElementById(browser, id) { - return await browser.$(`[data-id="${id}"]`); + const elem = await browser.$(`[data-id="${id}"]`); + elem['id'] = id; + return elem; } async function getCategory(browser, categoryName) { const categories = await browser.$$('.blocklyTreeLabel'); @@ -131,15 +137,77 @@ async function getBlockTypeFromCategory(browser, categoryName, blockType) { .getWorkspace() .getBlocksByType(blockType)[0].id; }, blockType); - return await browser.$(`[data-id="${id}"]`); + return getBlockElementById(browser, id); +} + +async function getLocationOfBlockConnection(browser, id, connectionName) { + return await browser.execute( + (id, connectionName) => { + const block = Blockly.getMainWorkspace().getBlockById(id); + + let connection; + switch (connectionName) { + case 'OUTPUT': + connection = block.outputConnection; + break; + case 'PREVIOUS': + connection = block.previousConnection; + break; + case 'NEXT': + connection = block.nextConnection; + break; + default: + connection = block.getInput(connectionName).connection; + break; + } + + const loc = Blockly.utils.Coordinate.sum( + block.getRelativeToSurfaceXY(), + connection.getOffsetInBlock() + ); + return Blockly.utils.svgMath.wsToScreenCoordinates( + Blockly.getMainWorkspace(), + loc + ); + }, + id, + connectionName + ); +} + +async function connect( + browser, + draggedBlock, + draggedConnection, + targetBlock, + targetConnection +) { + const draggedLocation = await getLocationOfBlockConnection( + browser, + draggedBlock.id, + draggedConnection + ); + const targetLocation = await getLocationOfBlockConnection( + browser, + targetBlock.id, + targetConnection + ); + + const delta = { + x: targetLocation.x - draggedLocation.x, + y: targetLocation.y - draggedLocation.y, + }; + await draggedBlock.dragAndDrop(delta); } module.exports = { testSetup, testFileLocations, getSelectedBlockElement, + getSelectedBlockId, getBlockElementById, getCategory, getNthBlockOfCategory, getBlockTypeFromCategory, + connect, };