Skip to content

Commit 794495d

Browse files
committed
chore: Implement initial block navigation tests.
1 parent d3dc71d commit 794495d

File tree

4 files changed

+187
-11
lines changed

4 files changed

+187
-11
lines changed

test/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,9 @@ document.addEventListener('DOMContentLoaded', () => {
129129
addP5();
130130
createWorkspace();
131131
document.getElementById('run')?.addEventListener('click', runCode);
132+
// Add Blockly to the global scope so that test code can access it to
133+
// verify state after keypresses.
134+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
135+
// @ts-expect-error
136+
window.Blockly = Blockly;
132137
});

test/loadTestBlocks.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,15 +182,15 @@ const simpleCircle = {
182182
'blocks': [
183183
{
184184
'type': 'p5_setup',
185-
'id': '5.{;T}3Qv}Awi:1M$:ut',
185+
'id': 'setup_root',
186186
'x': 0,
187187
'y': 75,
188188
'deletable': false,
189189
'inputs': {
190190
'STATEMENTS': {
191191
'block': {
192192
'type': 'p5_canvas',
193-
'id': 'spya_H-5F=K8+DhedX$y',
193+
'id': 'create_canvas_1',
194194
'deletable': false,
195195
'movable': false,
196196
'fields': {
@@ -200,12 +200,12 @@ const simpleCircle = {
200200
'next': {
201201
'block': {
202202
'type': 'p5_background_color',
203-
'id': 'i/Hvi~^DYffkN/WpT_Ck',
203+
'id': 'set_background_color_1',
204204
'inputs': {
205205
'COLOR': {
206206
'shadow': {
207207
'type': 'colour_picker',
208-
'id': 'B:zpi7kg+.GF_Dutd9GL',
208+
'id': 'set_background_color_1_color',
209209
'fields': {
210210
'COLOUR': '#9999ff',
211211
},
@@ -220,7 +220,7 @@ const simpleCircle = {
220220
},
221221
{
222222
'type': 'p5_draw',
223-
'id': '3iI4f%2#Gmk}=OjI7(8h',
223+
'id': 'draw_root',
224224
'x': 0,
225225
'y': 332,
226226
'deletable': false,
@@ -234,7 +234,7 @@ const simpleCircle = {
234234
'COLOR': {
235235
'shadow': {
236236
'type': 'colour_picker',
237-
'id': 'gq(POne}j:hVw%C3t{vx',
237+
'id': 'draw_circle_1_color',
238238
'fields': {
239239
'COLOUR': '#ffff00',
240240
},

test/webdriverio/test/basic_test.ts

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@
66

77
import * as chai from 'chai';
88
import * as Blockly from 'blockly';
9-
import {testSetup, testFileLocations, PAUSE_TIME} from './test_setup.js';
9+
import {
10+
focusWorkspace,
11+
setCurrentCursorNodeById,
12+
getCurrentCursorNodeFieldName,
13+
getCurrentCursorNodeId,
14+
getCurrentCursorNodeType,
15+
testSetup,
16+
testFileLocations,
17+
PAUSE_TIME,
18+
} from './test_setup.js';
1019
import {Key} from 'webdriverio';
1120

1221
suite('Keyboard navigation', function () {
@@ -27,10 +36,7 @@ suite('Keyboard navigation', function () {
2736
});
2837

2938
test('Selected block', async function () {
30-
const workspace = await this.browser.$(
31-
'#blocklyDiv > div > svg.blocklySvg > g',
32-
);
33-
await workspace.click();
39+
await focusWorkspace(this.browser);
3440
await this.browser.pause(PAUSE_TIME);
3541

3642
for (let i = 0; i < 9; i++) {
@@ -43,4 +49,89 @@ suite('Keyboard navigation', function () {
4349
});
4450
chai.assert.equal(selectedId, 'draw_circle_1');
4551
});
52+
53+
test('Down from statement block selects next connection', async function () {
54+
await focusWorkspace(this.browser);
55+
await this.browser.pause(PAUSE_TIME);
56+
await setCurrentCursorNodeById(this.browser, 'create_canvas_1');
57+
await this.browser.pause(PAUSE_TIME);
58+
await this.browser.keys(Key.ArrowDown);
59+
await this.browser.pause(PAUSE_TIME);
60+
61+
chai.assert.equal(
62+
await getCurrentCursorNodeId(this.browser),
63+
'create_canvas_1',
64+
);
65+
chai.assert.equal(
66+
await getCurrentCursorNodeType(this.browser),
67+
Blockly.ASTNode.types.NEXT,
68+
);
69+
});
70+
71+
test("Up from statement block selects previous block's connection", async function () {
72+
await focusWorkspace(this.browser);
73+
await this.browser.pause(PAUSE_TIME);
74+
await setCurrentCursorNodeById(this.browser, 'set_background_color_1');
75+
await this.browser.pause(PAUSE_TIME);
76+
await this.browser.keys(Key.ArrowUp);
77+
await this.browser.pause(PAUSE_TIME);
78+
79+
chai.assert.equal(
80+
await getCurrentCursorNodeId(this.browser),
81+
'create_canvas_1',
82+
);
83+
chai.assert.equal(
84+
await getCurrentCursorNodeType(this.browser),
85+
Blockly.ASTNode.types.NEXT,
86+
);
87+
});
88+
89+
test('Down from parent block selects input connection', async function () {
90+
await focusWorkspace(this.browser);
91+
await this.browser.pause(PAUSE_TIME);
92+
await setCurrentCursorNodeById(this.browser, 'setup_root');
93+
await this.browser.pause(PAUSE_TIME);
94+
await this.browser.keys(Key.ArrowDown);
95+
await this.browser.pause(PAUSE_TIME);
96+
97+
chai.assert.equal(await getCurrentCursorNodeId(this.browser), 'setup_root');
98+
chai.assert.equal(
99+
await getCurrentCursorNodeType(this.browser),
100+
Blockly.ASTNode.types.INPUT,
101+
);
102+
});
103+
104+
test('Up from child block selects input connection', async function () {
105+
await focusWorkspace(this.browser);
106+
await this.browser.pause(PAUSE_TIME);
107+
await setCurrentCursorNodeById(this.browser, 'create_canvas_1');
108+
await this.browser.pause(PAUSE_TIME);
109+
await this.browser.keys(Key.ArrowUp);
110+
await this.browser.pause(PAUSE_TIME);
111+
112+
chai.assert.equal(await getCurrentCursorNodeId(this.browser), 'setup_root');
113+
chai.assert.equal(
114+
await getCurrentCursorNodeType(this.browser),
115+
Blockly.ASTNode.types.INPUT,
116+
);
117+
});
118+
119+
test('Right from block selects field', async function () {
120+
await focusWorkspace(this.browser);
121+
await this.browser.pause(PAUSE_TIME);
122+
await setCurrentCursorNodeById(this.browser, 'create_canvas_1');
123+
await this.browser.pause(PAUSE_TIME);
124+
await this.browser.keys(Key.ArrowRight);
125+
await this.browser.pause(PAUSE_TIME);
126+
127+
chai.assert.equal(await getCurrentCursorNodeId(this.browser), 'create_canvas_1');
128+
chai.assert.equal(
129+
await getCurrentCursorNodeType(this.browser),
130+
Blockly.ASTNode.types.FIELD,
131+
);
132+
chai.assert.equal(
133+
await getCurrentCursorNodeFieldName(this.browser),
134+
'WIDTH',
135+
);
136+
});
46137
});

test/webdriverio/test/test_setup.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,86 @@ export async function getSelectedBlockId(browser: WebdriverIO.Browser) {
155155
});
156156
}
157157

158+
/**
159+
* Clicks in the workspace to focus it.
160+
*
161+
* @param browser The active WebdriverIO Browser object.
162+
*/
163+
export async function focusWorkspace(browser: WebdriverIO.Browser) {
164+
const workspaceElement = await browser.$(
165+
'#blocklyDiv > div > svg.blocklySvg > g',
166+
);
167+
await workspaceElement.click();
168+
}
169+
170+
/**
171+
* Select a block with the given id as the current cursor node.
172+
*
173+
* @param browser The active WebdriverIO Browser object.
174+
* @param blockId The id of the block to select.
175+
*/
176+
export async function setCurrentCursorNodeById(
177+
browser: WebdriverIO.Browser,
178+
blockId: string,
179+
) {
180+
return await browser.execute((blockId) => {
181+
const workspaceSvg = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
182+
const rootBlock = workspaceSvg.getBlockById(blockId);
183+
workspaceSvg
184+
.getCursor()
185+
?.setCurNode(Blockly.ASTNode.createBlockNode(rootBlock!)!);
186+
}, blockId);
187+
}
188+
189+
/**
190+
* Get the ID of the block at the current cursor node.
191+
*
192+
* @param browser The active WebdriverIO Browser object.
193+
* @returns A Promise that resolves to the ID of the current cursor node.
194+
*/
195+
export async function getCurrentCursorNodeId(
196+
browser: WebdriverIO.Browser,
197+
): Promise<string | undefined> {
198+
return await browser.execute(() => {
199+
const workspaceSvg = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
200+
return workspaceSvg.getCursor()?.getCurNode()?.getSourceBlock()?.id;
201+
});
202+
}
203+
204+
/**
205+
* Get the type of the current cursor node.
206+
*
207+
* @param browser The active WebdriverIO Browser object.
208+
* @returns A Promise that resolves to the type of the current cursor node.
209+
*/
210+
export async function getCurrentCursorNodeType(
211+
browser: WebdriverIO.Browser,
212+
): Promise<string | undefined> {
213+
return await browser.execute(() => {
214+
const workspaceSvg = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
215+
return workspaceSvg.getCursor()?.getCurNode()?.getType();
216+
});
217+
}
218+
219+
/**
220+
* Get the field name of the current cursor node.
221+
*
222+
* @param browser The active WebdriverIO Browser object.
223+
* @returns A Promise that resolves to the field name of the current cursor node.
224+
*/
225+
export async function getCurrentCursorNodeFieldName(
226+
browser: WebdriverIO.Browser,
227+
): Promise<string | undefined> {
228+
return await browser.execute(() => {
229+
const workspaceSvg = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
230+
const field = workspaceSvg
231+
.getCursor()
232+
?.getCurNode()
233+
?.getLocation() as Blockly.Field;
234+
return field.name;
235+
});
236+
}
237+
158238
export interface ElementWithId extends WebdriverIO.Element {
159239
id: string;
160240
}

0 commit comments

Comments
 (0)