@@ -13,6 +13,9 @@ import {
1313 tabNavigateToWorkspace ,
1414 testFileLocations ,
1515 testSetup ,
16+ sendKeyAndWait ,
17+ keyDown ,
18+ keyRight ,
1619} from './test_setup.js' ;
1720
1821suite ( 'Move tests' , function ( ) {
@@ -145,6 +148,62 @@ suite('Move tests', function () {
145148 await this . browser . keys ( Key . Escape ) ;
146149 }
147150 } ) ;
151+
152+ // When a top-level block with no previous, next or output
153+ // connections is subject to a constrained move, it should not move.
154+ //
155+ // This includes a regression test for issue #446 (fixed in PR #599)
156+ // where, due to an implementation error in Mover, constrained
157+ // movement following unconstrained movement it would result in the
158+ // block unexpectedly moving (unless workspace scale was === 1)
159+ test ( 'Constrained move of unattachable top-level block' , async function ( ) {
160+ // Block ID of an unconnectable block.
161+ const BLOCK = 'p5_setup_1' ;
162+
163+ // Scale workspace.
164+ await this . browser . execute ( ( ) => {
165+ ( Blockly . getMainWorkspace ( ) as Blockly . WorkspaceSvg ) . setScale ( 0.9 ) ;
166+ } ) ;
167+
168+ // Navigate to unconnectable block, get initial coords and start move.
169+ await tabNavigateToWorkspace ( this . browser ) ;
170+ await focusOnBlock ( this . browser , BLOCK ) ;
171+ const startCoordinate = await getCoordinate ( this . browser , BLOCK ) ;
172+ await this . browser . keys ( 'm' ) ;
173+
174+ // Check constrained moves have no effect.
175+ await keyDown ( this . browser , 5 ) ;
176+ let coordinate = await getCoordinate ( this . browser , BLOCK ) ;
177+ chai . assert . deepEqual (
178+ coordinate ,
179+ startCoordinate ,
180+ 'constrained move should have no effect' ,
181+ ) ;
182+
183+ // Unconstrained moves.
184+ await sendKeyAndWait ( this . browser , [ Key . Alt , Key . ArrowDown ] ) ;
185+ await sendKeyAndWait ( this . browser , [ Key . Alt , Key . ArrowRight ] ) ;
186+ const newCoordinate = await getCoordinate ( this . browser , BLOCK ) ;
187+ chai . assert . notDeepEqual (
188+ newCoordinate ,
189+ startCoordinate ,
190+ 'unconstrained move should have effect' ,
191+ ) ;
192+
193+ // Try multiple constrained moves, as first might (correctly) do nothing.
194+ for ( let i = 0 ; i < 5 ; i ++ ) {
195+ await keyDown ( this . browser ) ;
196+ const coordinate = await getCoordinate ( this . browser , BLOCK ) ;
197+ chai . assert . deepEqual (
198+ coordinate ,
199+ newCoordinate ,
200+ 'constrained move after unconstrained move should have no effect' ,
201+ ) ;
202+ }
203+
204+ // Abort move.
205+ await this . browser . keys ( Key . Escape ) ;
206+ } ) ;
148207} ) ;
149208
150209/**
@@ -218,3 +277,22 @@ function getConnectedBlockInfo(browser: Browser, id: string, index: number) {
218277 index ,
219278 ) ;
220279}
280+
281+ /**
282+ * Given a block ID, get the coordinates of that block, as returned by
283+ * .getRelativeTosSurfaceXY().
284+ *
285+ * @param browser The webdriverio browser session.
286+ * @param id The ID of the block having the connection we wish to examine.
287+ * @returns The coordinates of the block.
288+ */
289+ function getCoordinate (
290+ browser : Browser ,
291+ id : string ,
292+ ) : Promise < Blockly . utils . Coordinate > {
293+ return browser . execute ( ( id : string ) => {
294+ const block = Blockly . getMainWorkspace ( ) . getBlockById ( id ) ;
295+ if ( ! block ) throw new Error ( 'block not found' ) ;
296+ return block . getRelativeToSurfaceXY ( ) ;
297+ } , id ) ;
298+ }
0 commit comments