Skip to content
2 changes: 1 addition & 1 deletion web/libs/editor/tests/e2e/fragments/AtDateTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module.exports = {
{ id: this._dateInputId },
);

I.fillField(`#${this._dateInputId}`, "01020304");
await I.fillField(`#${this._dateInputId}`, "01020304");

const format = await I.executeScript(
({ id }) => {
Expand Down
5 changes: 3 additions & 2 deletions web/libs/editor/tests/e2e/fragments/Modals.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
const { I } = inject();

module.exports = {
seeWarning(text) {
async seeWarning(text) {
I.seeElement(".ant-modal");
I.see("Warning");
// Wait for modal content to be fully rendered
await I.wait(0.5);
I.see(text);
I.waitTicks(3);
I.see("OK");
},
dontSeeWarning(text) {
Expand Down
50 changes: 40 additions & 10 deletions web/libs/editor/tests/e2e/tests/audio/audio-regions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,26 @@ FFlagMatrix(["fflag_feat_front_lsdv_e_278_contextual_scrolling_short"], (flags)

// creating a new region
I.pressKey("1");
I.waitTicks(2); // Wait for label selection to update
AtAudioView.dragAudioElement(160, 80);
I.pressKey("u");
I.waitTicks(3); // Wait for deselection to complete

AtOutliner.seeRegions(2);

AtAudioView.clickAt(170);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion();
AtAudioView.clickAt(170);
I.waitTicks(2); // Wait for deselection
AtOutliner.dontSeeSelectedRegion();
AtAudioView.dragAudioElement(170, 40);
I.waitTicks(2); // Wait for region selection after drag
AtOutliner.seeSelectedRegion();
AtAudioView.clickAt(220);
I.waitTicks(2); // Wait for deselection
AtOutliner.dontSeeSelectedRegion();
})
.tag("@flakey")
.retry(3);
});

// Don't need to test this for both scenarios of flags, as it is the same code and is verified in the above test
if (!flags.fflag_feat_front_lsdv_e_278_contextual_scrolling_short) {
Expand All @@ -128,34 +132,41 @@ FFlagMatrix(["fflag_feat_front_lsdv_e_278_contextual_scrolling_short"], (flags)
for (let i = 0; i < 10; i++) {
// creating a new region
I.pressKey("1");
I.waitTicks(2); // Wait for label selection
AtLabels.seeSelectedLabel("Speech");
AtAudioView.dragAudioElement(40 * i + 10, 30);
I.waitTicks(2); // Wait for region creation
AtOutliner.dontSeeSelectedRegion();
AtAudioView.clickAt(40 * i + 20);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion();
I.pressKey("2");
I.waitTicks(2); // Wait for label change
I.pressKey("1");
I.waitTicks(2); // Wait for label change
I.pressKey("u");
I.waitTicks(2); // Wait for deselection
}

AtOutliner.seeRegions(10);

for (let i = 0; i < 10; i++) {
// creating a new region
AtAudioView.clickAt(40 * i + 20);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion();
I.pressKey("u");
I.waitTicks(2); // Wait for deselection
}

AtOutliner.seeRegions(10);

I.pressKey("u");
I.waitTicks(2); // Wait for deselection

AtOutliner.dontSeeSelectedRegion();
},
)
.tag("@flakey")
.retry(3);
);

FFlagScenario("Can select a region below a hidden region", async ({ I, LabelStudio, AtAudioView, AtOutliner }) => {
LabelStudio.setFeatureFlags({
Expand All @@ -171,31 +182,36 @@ FFlagMatrix(["fflag_feat_front_lsdv_e_278_contextual_scrolling_short"], (flags)

// create a new region
I.pressKey("1");
I.waitTicks(2); // Wait for label selection
AtAudioView.dragAudioElement(50, 80);
I.pressKey("u");
I.waitTicks(2); // Wait for deselection

AtOutliner.seeRegions(1);

// create a new region above the first one
I.pressKey("2");
I.waitTicks(2); // Wait for label selection
AtAudioView.dragAudioElement(49, 81);
I.pressKey("u");
I.waitTicks(2); // Wait for deselection

AtOutliner.seeRegions(2);

// click on the top-most region visible to select it
AtAudioView.clickAt(51);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion("Noise");

// hide the region
AtOutliner.toggleRegionVisibility("Noise");
I.waitTicks(2); // Wait for visibility change

// click on the region below the hidden one to select it
AtAudioView.clickAt(51);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion("Speech");
})
.tag("@flakey")
.retry(3);
});

FFlagScenario(
"Selecting a region brings it to the front of the stack",
Expand All @@ -213,33 +229,41 @@ FFlagMatrix(["fflag_feat_front_lsdv_e_278_contextual_scrolling_short"], (flags)

// create a new region
I.pressKey("1");
I.waitTicks(2); // Wait for label selection
AtAudioView.dragAudioElement(50, 80);
I.pressKey("u");
I.waitTicks(2); // Wait for deselection

AtOutliner.seeRegions(1);

// create a new region above the first one
I.pressKey("2");
I.waitTicks(2); // Wait for label selection
AtAudioView.dragAudioElement(49, 81);
I.pressKey("u");
I.waitTicks(2); // Wait for deselection

AtOutliner.seeRegions(2);

// click on the top-most region visible to select it
AtAudioView.clickAt(51);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion("Noise");

// Select the bottom most region to bring it to the top
AtOutliner.clickRegion("Speech");
I.waitTicks(2); // Wait for region selection and z-index change
AtOutliner.seeSelectedRegion("Speech");

// click on the overlapping region will deselect it, which shows that it is now the top in the list
AtAudioView.clickAt(51);
I.waitTicks(2); // Wait for deselection
AtOutliner.dontSeeSelectedRegion("Speech");
AtOutliner.dontSeeSelectedRegion("Noise");

// click on the overlapping region will select the top item of the list, which will now be the item which was brought to the front by the original interaction.
AtAudioView.clickAt(51);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion("Speech");
},
);
Expand Down Expand Up @@ -282,25 +306,31 @@ FFlagMatrix(["fflag_feat_front_lsdv_e_278_contextual_scrolling_short"], (flags)

// creating a new region
I.pressKey("1");
I.waitTicks(2); // Wait for label selection
AtAudioView.dragAudioElement(300, 80);
I.pressKey("u");
I.waitTicks(2); // Wait for deselection

// creating a ghost region
I.pressKey("1");
I.waitTicks(2); // Wait for label selection
AtAudioView.dragAudioElement(160, 80, false);
I.pressKey("1");
I.waitTicks(2);
I.pressMouseUp();
I.waitTicks(2);
I.waitTicks(3); // Increased wait for state cleanup

// checking if the created region is selected
AtAudioView.clickAt(310);
I.waitTicks(2); // Wait for region selection
AtOutliner.seeSelectedRegion();

// trying to select the ghost region, if there is no ghost region, the region will keep selected
// as ghost region is not selectable and impossible to change the label, the created region will be deselected if there is a ghost region created.
AtAudioView.clickAt(170);
I.waitTicks(2); // Wait for click processing
I.pressKey("2");
I.waitTicks(2); // Wait for label change
AtOutliner.seeSelectedRegion();

AtOutliner.seeRegions(2);
Expand Down
29 changes: 29 additions & 0 deletions web/libs/editor/tests/e2e/tests/image.transformer.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const assert = require("assert");
const Asserts = require("../utils/asserts");
const Helpers = require("./helpers");
const { waitForTransformerState } = require("../utils/async-helpers");

Feature("Image transformer");

Expand Down Expand Up @@ -171,25 +172,37 @@ Data(shapesTable).Scenario(

// Select the first region
AtImageView.clickAt(...getCenter(bbox1));
I.wait(0.1); // Allow click to register
AtOutliner.seeSelectedRegion();

// Wait for transformer to initialize and render
await waitForTransformerState(I, Shape.hasTransformer, "transformer");

// Match if transformer exist with expectations in single selected mode
isTransformerExist = await AtImageView.isTransformerExist();
assert.strictEqual(isTransformerExist, Shape.hasTransformer);

// Wait for rotator to render
await waitForTransformerState(I, Shape.hasRotator, "rotator");

// Match if rotator at transformer exist with expectations in single selected mode
isTransformerExist = await AtImageView.isRotaterExist();
assert.strictEqual(isTransformerExist, Shape.hasRotator);

// Switch to move tool
I.pressKey("v");
I.wait(0.1); // Allow tool switch to register

// Wait for move tool transformer to initialize
await waitForTransformerState(I, Shape.hasMoveToolTransformer, "transformer");

// Match if rotator at transformer exist with expectations in single selected mode with move tool chosen
isTransformerExist = await AtImageView.isTransformerExist();
assert.strictEqual(isTransformerExist, Shape.hasMoveToolTransformer);

// Deselect the previous selected region
I.pressKey(["u"]);
I.wait(0.1); // Allow deselection to register

// Select 2 regions
AtImageView.drawThroughPoints(
Expand All @@ -200,11 +213,18 @@ Data(shapesTable).Scenario(
"steps",
10,
);
I.wait(0.1); // Allow multi-selection to complete

// Wait for multi-selection transformer to initialize
await waitForTransformerState(I, Shape.hasMultiSelectionTransformer, "transformer");

// Match if transformer exist with expectations in multiple selected mode
isTransformerExist = await AtImageView.isTransformerExist();
assert.strictEqual(isTransformerExist, Shape.hasMultiSelectionTransformer);

// Wait for multi-selection rotator to initialize
await waitForTransformerState(I, Shape.hasMultiSelectionRotator, "rotator");

// Match if rotator exist with expectations in multiple selected mode
isTransformerExist = await AtImageView.isRotaterExist();
assert.strictEqual(isTransformerExist, Shape.hasMultiSelectionRotator);
Expand Down Expand Up @@ -246,14 +266,23 @@ Data(shapesTable.filter(({ shapeName }) => shapes[shapeName].hasMoveToolTransfor
// Transform the shape
// Move the top anchor up for 50px (limited by image border) => {x1:50,y1:0,x2:150,y2:150}
AtImageView.drawByDrag(100, 50, 0, -100);
I.waitTicks(3); // Wait for transformation to complete
// Move the left anchor left for 50px (limited by image border) => {x1:0,y1:0,x2:150,y2:150}
AtImageView.drawByDrag(50, 75, -300, -100);
I.waitTicks(3); // Wait for transformation to complete
// Move the right anchor left for 50px => {x1:0,y1:0,x2:100,y2:150}
AtImageView.drawByDrag(150, 75, -50, 0);
I.waitTicks(3); // Wait for transformation to complete
// Move the bottom anchor down for 100px => {x1:0,y1:0,x2:100,y2:250}
AtImageView.drawByDrag(50, 150, 10, 100);
I.waitTicks(3); // Wait for transformation to complete
// Move the right-bottom anchor right for 200px and down for 50px => {x1:0,y1:0,x2:300,y2:300}
AtImageView.drawByDrag(100, 250, 200, 50);
I.waitTicks(5); // Wait for final transformation to complete

// Wait for transformer to finish updating and region state to settle
I.wait(0.5);

// Check resulting sizes
const rectangleResult = await LabelStudio.serialize();
const exceptedResult = Shape.byBBox(0, 0, 300, 300).result;
Expand Down
28 changes: 25 additions & 3 deletions web/libs/editor/tests/e2e/tests/outliner.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const assert = require("assert");
const { centerOfBbox } = require("./helpers");
const { waitForMetaSaved } = require("../utils/async-helpers");

Feature("Outliner");

Expand Down Expand Up @@ -123,6 +124,7 @@ Scenario("Basic details", async ({ I, LabelStudio, AtOutliner, AtDetails }) => {
for (let idx = keys.length - 1; idx >= 0; idx--) {
I.pressKeyUp(keys[idx]);
}
I.wait(0.05); // Small wait between key sequences
}
};

Expand Down Expand Up @@ -195,14 +197,34 @@ Scenario("Basic details", async ({ I, LabelStudio, AtOutliner, AtDetails }) => {

I.say("Add new meta and check result");
AtDetails.clickEditMeta();

fillByPressKeyDown([["M"], ["Space"], ["1"], ["Shift", "Enter"], ["M"], ["Space"], ["2"], ["Enter"]]);

// Use fillMeta helper for reliability
AtDetails.fillMeta("M 1\nM 2");

// Click outside the meta field to blur it and trigger save
I.click(locate(".lsf-panel__title").withText("Details"));
I.wait(0.3); // Wait for meta to be saved after blur

AtDetails.seeMeta("M 1");
AtDetails.seeMeta("M 2");

// Wait for first meta to be fully committed
await waitForMetaSaved(I, 2, "M 1", { timeout: 5000 });

I.say("Add line to meta");
AtDetails.clickMeta();
fillByPressKeyDown([["Shift", "Enter"], ["3"], ["Enter"]]);
I.wait(0.3); // Wait for meta input to focus

// Clear and fill with updated meta value
AtDetails.fillMeta("M 1\nM 2\n3");

// Click outside the meta field to blur it and trigger save
I.click(locate(".lsf-panel__title").withText("Details"));
I.wait(0.3); // Wait for meta to be saved after blur

// Wait for meta to be actually saved in the annotation
await waitForMetaSaved(I, 2, "3", { timeout: 5000 });

AtDetails.seeMeta("3");
AtDetails.dontSeeMeta("23");

Expand Down
Loading
Loading