Skip to content

Commit c90aae9

Browse files
authored
chore: Implement initial block navigation tests. (#463)
* chore: Implement initial block navigation tests. * Fixed formatting. * Fixed lint warning. * Clarify test name.
1 parent 2129bb4 commit c90aae9

File tree

4 files changed

+185
-5
lines changed

4 files changed

+185
-5
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: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ const simpleCircle = {
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: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
import * as chai from 'chai';
88
import * as Blockly from 'blockly';
99
import {
10+
focusWorkspace,
11+
setCurrentCursorNodeById,
12+
getCurrentCursorNodeFieldName,
13+
getCurrentCursorNodeId,
14+
getCurrentCursorNodeType,
1015
testSetup,
1116
testFileLocations,
1217
PAUSE_TIME,
@@ -47,4 +52,92 @@ suite('Keyboard navigation', function () {
4752
});
4853
chai.assert.equal(selectedId, 'draw_circle_1');
4954
});
55+
56+
test('Down from statement block selects next connection', async function () {
57+
await focusWorkspace(this.browser);
58+
await this.browser.pause(PAUSE_TIME);
59+
await setCurrentCursorNodeById(this.browser, 'create_canvas_1');
60+
await this.browser.pause(PAUSE_TIME);
61+
await this.browser.keys(Key.ArrowDown);
62+
await this.browser.pause(PAUSE_TIME);
63+
64+
chai.assert.equal(
65+
await getCurrentCursorNodeId(this.browser),
66+
'create_canvas_1',
67+
);
68+
chai.assert.equal(
69+
await getCurrentCursorNodeType(this.browser),
70+
Blockly.ASTNode.types.NEXT,
71+
);
72+
});
73+
74+
test("Up from statement block selects previous block's connection", async function () {
75+
await focusWorkspace(this.browser);
76+
await this.browser.pause(PAUSE_TIME);
77+
await setCurrentCursorNodeById(this.browser, 'set_background_color_1');
78+
await this.browser.pause(PAUSE_TIME);
79+
await this.browser.keys(Key.ArrowUp);
80+
await this.browser.pause(PAUSE_TIME);
81+
82+
chai.assert.equal(
83+
await getCurrentCursorNodeId(this.browser),
84+
'create_canvas_1',
85+
);
86+
chai.assert.equal(
87+
await getCurrentCursorNodeType(this.browser),
88+
Blockly.ASTNode.types.NEXT,
89+
);
90+
});
91+
92+
test('Down from parent block selects input connection', async function () {
93+
await focusWorkspace(this.browser);
94+
await this.browser.pause(PAUSE_TIME);
95+
await setCurrentCursorNodeById(this.browser, 'p5_setup_1');
96+
await this.browser.pause(PAUSE_TIME);
97+
await this.browser.keys(Key.ArrowDown);
98+
await this.browser.pause(PAUSE_TIME);
99+
100+
chai.assert.equal(await getCurrentCursorNodeId(this.browser), 'p5_setup_1');
101+
chai.assert.equal(
102+
await getCurrentCursorNodeType(this.browser),
103+
Blockly.ASTNode.types.INPUT,
104+
);
105+
});
106+
107+
test('Up from child block selects input connection', async function () {
108+
await focusWorkspace(this.browser);
109+
await this.browser.pause(PAUSE_TIME);
110+
await setCurrentCursorNodeById(this.browser, 'create_canvas_1');
111+
await this.browser.pause(PAUSE_TIME);
112+
await this.browser.keys(Key.ArrowUp);
113+
await this.browser.pause(PAUSE_TIME);
114+
115+
chai.assert.equal(await getCurrentCursorNodeId(this.browser), 'p5_setup_1');
116+
chai.assert.equal(
117+
await getCurrentCursorNodeType(this.browser),
118+
Blockly.ASTNode.types.INPUT,
119+
);
120+
});
121+
122+
test('Right from block selects first field', async function () {
123+
await focusWorkspace(this.browser);
124+
await this.browser.pause(PAUSE_TIME);
125+
await setCurrentCursorNodeById(this.browser, 'create_canvas_1');
126+
await this.browser.pause(PAUSE_TIME);
127+
await this.browser.keys(Key.ArrowRight);
128+
await this.browser.pause(PAUSE_TIME);
129+
130+
chai.assert.equal(
131+
await getCurrentCursorNodeId(this.browser),
132+
'create_canvas_1',
133+
);
134+
chai.assert.equal(
135+
await getCurrentCursorNodeType(this.browser),
136+
Blockly.ASTNode.types.FIELD,
137+
);
138+
chai.assert.equal(
139+
await getCurrentCursorNodeFieldName(this.browser),
140+
'WIDTH',
141+
);
142+
});
50143
});

test/webdriverio/test/test_setup.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,88 @@ 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+
if (rootBlock) {
184+
workspaceSvg
185+
.getCursor()
186+
?.setCurNode(Blockly.ASTNode.createBlockNode(rootBlock));
187+
}
188+
}, blockId);
189+
}
190+
191+
/**
192+
* Get the ID of the block at the current cursor node.
193+
*
194+
* @param browser The active WebdriverIO Browser object.
195+
* @returns A Promise that resolves to the ID of the current cursor node.
196+
*/
197+
export async function getCurrentCursorNodeId(
198+
browser: WebdriverIO.Browser,
199+
): Promise<string | undefined> {
200+
return await browser.execute(() => {
201+
const workspaceSvg = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
202+
return workspaceSvg.getCursor()?.getCurNode()?.getSourceBlock()?.id;
203+
});
204+
}
205+
206+
/**
207+
* Get the type of the current cursor node.
208+
*
209+
* @param browser The active WebdriverIO Browser object.
210+
* @returns A Promise that resolves to the type of the current cursor node.
211+
*/
212+
export async function getCurrentCursorNodeType(
213+
browser: WebdriverIO.Browser,
214+
): Promise<string | undefined> {
215+
return await browser.execute(() => {
216+
const workspaceSvg = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
217+
return workspaceSvg.getCursor()?.getCurNode()?.getType();
218+
});
219+
}
220+
221+
/**
222+
* Get the field name of the current cursor node.
223+
*
224+
* @param browser The active WebdriverIO Browser object.
225+
* @returns A Promise that resolves to the field name of the current cursor node.
226+
*/
227+
export async function getCurrentCursorNodeFieldName(
228+
browser: WebdriverIO.Browser,
229+
): Promise<string | undefined> {
230+
return await browser.execute(() => {
231+
const workspaceSvg = Blockly.getMainWorkspace() as Blockly.WorkspaceSvg;
232+
const field = workspaceSvg
233+
.getCursor()
234+
?.getCurNode()
235+
?.getLocation() as Blockly.Field;
236+
return field.name;
237+
});
238+
}
239+
158240
export interface ElementWithId extends WebdriverIO.Element {
159241
id: string;
160242
}

0 commit comments

Comments
 (0)