Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions src/actions/enter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
renderManagement,
comments,
getFocusManager,
hasBubble,
} from 'blockly/core';

import type {Block} from 'blockly/core';
Expand Down Expand Up @@ -163,13 +164,11 @@ export class EnterAction {
// opening a bubble of some sort. We then need to wait for the bubble to
// appear before attempting to navigate into it.
curNode.onClick();
// This currently only works for MutatorIcons.
// See icon_navigation_policy.
if (curNode instanceof icons.MutatorIcon) {
renderManagement.finishQueuedRenders().then(() => {
renderManagement.finishQueuedRenders().then(() => {
if (hasBubble(curNode) && curNode.bubbleIsVisible()) {
cursor.in();
});
}
}
});
return true;
} else if (curNode instanceof comments.CommentBarButton) {
curNode.performAction();
Expand Down
8 changes: 8 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,14 @@ export class KeyboardNavigation {
stroke: var(--blockly-active-node-color);
stroke-width: var(--blockly-selection-width);
}

/* The workspace itself is the active node. */
.blocklyKeyboardNavigation
.blocklyBubble.blocklyActiveFocus
.blocklyDraggable {
stroke: var(--blockly-active-node-color);
stroke-width: var(--blockly-selection-width);
}
`);

// Keyboard-nav-specific styling for the context menu.
Expand Down
103 changes: 103 additions & 0 deletions test/webdriverio/test/block_comment_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as chai from 'chai';
import * as Blockly from 'blockly';
import {
focusOnBlock,
getCurrentFocusNodeId,
testSetup,
sendKeyAndWait,
testFileLocations,
keyRight,
} from './test_setup.js';
import {Key} from 'webdriverio';

suite('Block comment navigation', function () {
// Setting timeout to unlimited as these tests take a longer time to run than most mocha test
this.timeout(0);

// Setup Selenium for all of the tests
setup(async function () {
this.browser = await testSetup(testFileLocations.NAVIGATION_TEST_BLOCKS);
await this.browser.execute(() => {
Blockly.getMainWorkspace()
.getBlockById('p5_canvas_1')
?.setCommentText('test comment');
});
});

test('Activating a block comment icon focuses the comment', async function () {
await focusOnBlock(this.browser, 'p5_canvas_1');
await keyRight(this.browser);
await sendKeyAndWait(this.browser, Key.Enter);
const focusedNodeId = await getCurrentFocusNodeId(this.browser);
chai.assert.equal(focusedNodeId, 'blockly-2s_comment_textarea_');
});

test('Escape from a focused comment focuses its bubble', async function () {
await focusOnBlock(this.browser, 'p5_canvas_1');
await keyRight(this.browser);
await sendKeyAndWait(this.browser, Key.Enter);
await sendKeyAndWait(this.browser, Key.Escape);
const bubbleFocused = await this.browser.execute(() => {
return (
Blockly.getFocusManager().getFocusedNode() ===
Blockly.getMainWorkspace()
.getBlockById('p5_canvas_1')
?.getIcon(Blockly.icons.IconType.COMMENT)
?.getBubble()
);
});
chai.assert.isTrue(bubbleFocused);
});

test('Double Escape from a focused comment closes its bubble', async function () {
await focusOnBlock(this.browser, 'p5_canvas_1');
await keyRight(this.browser);
await sendKeyAndWait(this.browser, Key.Enter);
await sendKeyAndWait(this.browser, Key.Escape);
await sendKeyAndWait(this.browser, Key.Escape);
const bubbleVisible = await this.browser.execute(() => {
return Blockly.getMainWorkspace()
.getBlockById('p5_canvas_1')
?.getIcon(Blockly.icons.IconType.COMMENT)
?.bubbleIsVisible();
});
chai.assert.isFalse(bubbleVisible);
});

test('Double Escape from a focused comment focuses the comment icon', async function () {
await focusOnBlock(this.browser, 'p5_canvas_1');
await keyRight(this.browser);
await sendKeyAndWait(this.browser, Key.Enter);
await sendKeyAndWait(this.browser, Key.Escape);
await sendKeyAndWait(this.browser, Key.Escape);
const commentIconFocused = await this.browser.execute(() => {
return (
Blockly.getFocusManager().getFocusedNode() ===
Blockly.getMainWorkspace()
.getBlockById('p5_canvas_1')
?.getIcon(Blockly.icons.IconType.COMMENT)
);
});
chai.assert.isTrue(commentIconFocused);
});

test('Block comments can be edited', async function () {
await focusOnBlock(this.browser, 'p5_canvas_1');
await keyRight(this.browser);
await sendKeyAndWait(this.browser, Key.Enter);
await sendKeyAndWait(this.browser, 'Hello world');
await sendKeyAndWait(this.browser, Key.Escape);
const commentText = await this.browser.execute(() => {
return Blockly.getMainWorkspace()
.getBlockById('p5_canvas_1')
?.getCommentText();
});
chai.assert.equal(commentText, 'test commentHello world');
});
});
Loading