Skip to content
This repository was archived by the owner on Apr 18, 2024. It is now read-only.

Commit 8e5aba5

Browse files
BradNeubergbradneuberghlomzik
authored
fix: DEV-4081: e2e tests for selected region after tool changes (#1192)
* e2e tests to ensure selected region is correct after moving between certain tools. When using Brush then Eraser or Pan, existing region should stay selected and have new additions be added to it. Similar for the Magic Wand. We also have to ensure that the unselectRegionOnToolChange property for the Brush tool is updated on `afterCreate` so that e2e tests can dynamically update a feature flag and have it be applied. * Make sure common helper function is available. * Small code style fixes. * Ensure magicwand tag is feature flagged on imports, not dynamically in the Registry. This is safer for side effects. We've also modified our e2e tests to work with this different feature flagging approach. * Make changes based on code review feedback. --------- Co-authored-by: bradneuberg <[email protected]> Co-authored-by: hlomzik <[email protected]>
1 parent 9d3e834 commit 8e5aba5

File tree

4 files changed

+131
-15
lines changed

4 files changed

+131
-15
lines changed

e2e/tests/helpers.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const assert = require('assert');
2+
13
/**
24
* Load custom example
35
* @param {object} params
@@ -823,6 +825,16 @@ function hasSelectedRegion() {
823825
return !!Htx.annotationStore.selected.highlightedNode;
824826
}
825827

828+
async function doDrawingAction(I, { msg, fromX, fromY, toX, toY }) {
829+
I.usePlaywrightTo(msg, async ({ browser, browserContext, page }) => {
830+
await page.mouse.move(fromX, fromY);
831+
await page.mouse.down();
832+
await page.mouse.move(toX, toY);
833+
await page.mouse.up();
834+
});
835+
I.wait(1); // Ensure that the tool is fully finished being created.
836+
}
837+
826838
// `mulberry32` (simple generator with a 32-bit state)
827839
function createRandomWithSeed(seed) {
828840
return function() {
@@ -833,6 +845,7 @@ function createRandomWithSeed(seed) {
833845
return ((t ^ t >>> 14) >>> 0) / 4294967296;
834846
};
835847
}
848+
836849
function createRandomIntWithSeed(seed) {
837850
const random = createRandomWithSeed(seed);
838851

@@ -894,6 +907,7 @@ module.exports = {
894907
omitBy,
895908
dumpJSON,
896909

910+
doDrawingAction,
897911
createRandomWithSeed,
898912
createRandomIntWithSeed,
899913
};

e2e/tests/image.magic-wand.test.js

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const {
22
initLabelStudio,
3+
doDrawingAction,
34
hasKonvaPixelColorAtPoint,
45
setKonvaLayersOpacity,
56
serialize,
@@ -41,8 +42,6 @@ const annotationEmpty = {
4142
result: [],
4243
};
4344

44-
// TODO: Change these URLs to heartex URLs, and ensure the heartex bucket allows CORS access
45-
// for these to work.
4645
const data = {
4746
'image': [
4847
'http://htx-pub.s3.amazonaws.com/samples/magicwand/magic_wand_scale_1_20200902_015806_26_2235_1B_AnalyticMS_00750_00750.jpg',
@@ -53,16 +52,6 @@ const data = {
5352
'thumb': 'http://htx-pub.s3.amazonaws.com/samples/magicwand/magic_wand_thumbnail_20200902_015806_26_2235_1B_AnalyticMS_00750_00750.jpg',
5453
};
5554

56-
async function magicWand(I, { msg, fromX, fromY, toX, toY }) {
57-
I.usePlaywrightTo(msg, async ({ page }) => {
58-
await page.mouse.move(fromX, fromY);
59-
await page.mouse.down();
60-
await page.mouse.move(toX, toY);
61-
await page.mouse.up();
62-
});
63-
I.wait(1); // Ensure that the magic wand brush region is fully finished being created.
64-
}
65-
6655
async function assertMagicWandPixel(I, x, y, assertValue, rgbArray, msg) {
6756
const hasPixel = await I.executeScript(hasKonvaPixelColorAtPoint, [x, y, rgbArray, 1]);
6857

@@ -100,8 +89,8 @@ Scenario('Make sure the magic wand works in a variety of scenarios', async funct
10089
AtSidebar.seeRegions(0);
10190

10291
I.say('Magic wanding clouds with cloud class in upper left of image');
103-
await magicWand(I, { msg: 'Fill in clouds upper left', fromX: 258, fromY: 214, toX: 650, toY: 650 });
104-
await magicWand(I, { msg: 'Fill in clouds lower left', fromX: 337, fromY: 777, toX: 650, toY: 650 });
92+
await doDrawingAction(I, { msg: 'Fill in clouds upper left', fromX: 258, fromY: 214, toX: 650, toY: 650 });
93+
await doDrawingAction(I, { msg: 'Fill in clouds lower left', fromX: 337, fromY: 777, toX: 650, toY: 650 });
10594

10695
I.say('Ensuring repeated magic wands back to back with same class collapsed into single region');
10796
AtSidebar.seeRegions(1);
@@ -172,7 +161,7 @@ Scenario('Make sure the magic wand works in a variety of scenarios', async funct
172161
I.pressKey('2');
173162

174163
I.say('Magic wanding cloud shadows with cloud shadow class in center of zoomed image');
175-
await magicWand(I, { msg: 'Cloud shadow in middle of image', fromX: 390, fromY: 500, toX: 500, toY: 500 });
164+
await doDrawingAction(I, { msg: 'Cloud shadow in middle of image', fromX: 390, fromY: 500, toX: 500, toY: 500 });
176165

177166
I.say('Ensuring new cloud shadow magic wand region gets added to sidebar');
178167
AtSidebar.seeRegions(2);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/* global Feature, Scenario */
2+
3+
const {
4+
doDrawingAction,
5+
initLabelStudio,
6+
waitForImage,
7+
} = require('./helpers');
8+
const assert = require('assert');
9+
10+
Feature('Test Image Region Stay Selected Between Tools');
11+
12+
const PLANET = {
13+
color: '#00FF00',
14+
rgbArray: [0, 255, 0],
15+
};
16+
const MOONWALKER = {
17+
color: '#0000FF',
18+
rgbArray: [0, 0, 255],
19+
};
20+
21+
const config = `
22+
<View>
23+
<Image name="image" value="$image" crossOrigin="anonymous" />
24+
<Brush name="brush" toName="image" />
25+
<MagicWand name="magicwand" toName="image" />
26+
<Labels name="labels" toName="image" fillOpacity="0.5" strokeWidth="5">
27+
<Label value="Planet" background="${PLANET.color}"></Label>
28+
<Label value="Moonwalker" background="${MOONWALKER.color}"></Label>
29+
</Labels>
30+
</View>`;
31+
32+
const annotationEmpty = {
33+
id: '1000',
34+
result: [],
35+
};
36+
37+
const data = {
38+
image:
39+
'https://htx-misc.s3.amazonaws.com/opensource/label-studio/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg',
40+
};
41+
42+
async function testRegion(testType, toolAccelerator, I, LabelStudio, AtImageView, AtSidebar) {
43+
const params = {
44+
config,
45+
data,
46+
annotations: [annotationEmpty],
47+
};
48+
49+
LabelStudio.setFeatureFlags({
50+
'fflag_feat_front_dev_4081_magic_wand_tool': true,
51+
});
52+
53+
I.amOnPage('/');
54+
55+
I.executeScript(initLabelStudio, params);
56+
57+
AtImageView.waitForImage();
58+
await AtImageView.lookForStage();
59+
I.executeScript(waitForImage);
60+
61+
I.say(`Select ${testType} & planet class`);
62+
I.pressKey(toolAccelerator);
63+
I.pressKey('1');
64+
65+
I.say('There should be no regions initially');
66+
AtSidebar.seeRegions(0);
67+
68+
I.say(`${testType} initial region`);
69+
await doDrawingAction(I, { msg: `Initial ${testType}`, fromX: 150, fromY: 110, toX: 150+50, toY: 110+50 });
70+
71+
I.say('There should now be a single region');
72+
AtSidebar.seeRegions(1);
73+
74+
I.say(`Using Eraser on ${testType} region`);
75+
I.pressKey('E');
76+
I.usePlaywrightTo('Erasing', async ({ browser, browserContext, page }) => {
77+
await page.mouse.move(150, 150);
78+
await page.mouse.down();
79+
await page.mouse.move(150+100, 150);
80+
await page.mouse.up();
81+
});
82+
83+
I.say(`Doing another ${testType} with same class after erasing`);
84+
I.pressKey(toolAccelerator);
85+
await doDrawingAction(I, { msg: `${testType} after erasing`, fromX: 280, fromY: 480, toX: 280+50, toY: 480+50 });
86+
87+
I.say('There should still only be one region');
88+
AtSidebar.seeRegions(1);
89+
90+
I.say('Zooming and selecting pan tool');
91+
I.click('button[aria-label="zoom-in"]');
92+
I.click('button[aria-label="zoom-in"]');
93+
I.pressKey('H');
94+
95+
I.say(`Doing another ${testType} after zooming and selecting pan tool`);
96+
I.pressKey(toolAccelerator);
97+
await doDrawingAction(I, { msg: `${testType} after zoom and pan selected`,
98+
fromX: 400, fromY: 200, toX: 400+15, toY: 400+15 });
99+
100+
I.say('There should still only be one region');
101+
AtSidebar.seeRegions(1);
102+
}
103+
104+
Scenario('Selected brush region should stay between tools', async function({ I, LabelStudio, AtImageView, AtSidebar }) {
105+
await testRegion('brush', 'B', I, LabelStudio, AtImageView, AtSidebar);
106+
});
107+
108+
Scenario('Selected Magic Wand region should stay between tools', async function({ I, LabelStudio, AtImageView, AtSidebar }) {
109+
await testRegion('magicwand', 'W', I, LabelStudio, AtImageView, AtSidebar);
110+
});

src/tools/Brush.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ const _Tool = types
5353
group: 'segmentation',
5454
shortcut: 'B',
5555
smart: true,
56+
57+
// Support the existing unselect behavior until the Magic Wand feature flag is on by default.
58+
// @todo change to false once the Magic Wand is on by default.
5659
unselectRegionOnToolChange: isFF(FF_DEV_4081) ? false : true,
5760
})
5861
.volatile(() => ({

0 commit comments

Comments
 (0)