const assert = require("assert");
const { centerOfBbox } = require("./helpers");
Feature("Outliner");
const IMAGE =
"https://htx-pub.s3.us-east-1.amazonaws.com/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg";
Scenario("Basic details", async ({ I, LabelStudio, AtOutliner, AtDetails }) => {
const RESULT_LABELS = ["a", "b", "c"];
const getRectangleRegion = (results) => {
const region = results.find((item) => item.from_name === "rect" && item.type === "rectangle");
assert(region, "Rectangle region not found in serialized results");
return region;
};
const result = [
{
value: {
start: 0,
end: 4,
labels: ["a", "b", "c"],
},
id: "test_t_1",
from_name: "label",
to_name: "text",
type: "labels",
},
{
value: {
start: 5,
end: 6,
labels: [],
},
id: "test_t_2",
from_name: "label",
to_name: "text",
type: "labels",
},
{
value: {
x: 25,
y: 25,
width: 50,
height: 50,
},
id: "test_i_1",
from_name: "rect",
to_name: "img",
type: "rectangle",
},
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
x: 25,
y: 25,
width: 50,
height: 50,
rotation: 0,
},
id: "test_i_1",
from_name: "rect",
to_name: "img",
type: "rectangle",
origin: "manual",
},
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
x: 25,
y: 25,
width: 50,
height: 50,
rotation: 0,
rating: 4,
},
id: "test_i_1",
from_name: "rating",
to_name: "img",
type: "rating",
origin: "manual",
},
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
x: 25,
y: 25,
width: 50,
height: 50,
rotation: 0,
text: ["text", "area"],
},
id: "test_i_1",
from_name: "textarea",
to_name: "img",
type: "textarea",
origin: "manual",
},
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
x: 25,
y: 25,
width: 50,
height: 50,
rotation: 0,
choices: ["option 1", "option 2"],
},
id: "test_i_1",
from_name: "choices",
to_name: "img",
type: "choices",
origin: "manual",
},
];
const fillByPressKeyDown = (keysList) => {
for (const keys of keysList) {
for (let idx = 0; idx < keys.length; idx++) {
I.pressKeyDown(keys[idx]);
}
for (let idx = keys.length - 1; idx >= 0; idx--) {
I.pressKeyUp(keys[idx]);
}
}
};
I.amOnPage("/");
LabelStudio.init({
config: `
`,
data: {
text: "Just a text",
image: IMAGE,
},
annotations: [
{
id: "test",
result,
},
],
});
AtOutliner.seeRegions(3);
LabelStudio.waitForObjectsReady();
I.say("Select text region");
AtOutliner.clickRegion(1);
I.say("Check it's details");
for (const value of RESULT_LABELS) {
AtDetails.seeLabel(value);
}
AtDetails.seeLabels(RESULT_LABELS.length);
AtDetails.seeText("Just");
I.say("Select second text region");
AtOutliner.clickRegion(2);
I.say("Check it's details");
AtDetails.seeLabels(0);
AtDetails.seeText("a");
I.say("Select image region");
AtOutliner.clickRegion(3);
const isRelativeCoords = await LabelStudio.hasFF("fflag_fix_front_dev_3793_relative_coords_short");
if (isRelativeCoords) {
AtDetails.seeFieldWithValue("X", "25");
AtDetails.seeFieldWithValue("H", "50");
}
I.say("Check perregions displaying");
AtDetails.seeResultRating(4);
AtDetails.seeResultTextarea(["text", "area"]);
AtDetails.seeResultChoices(["option 1", "option 2"]);
I.say("Add new meta and check result");
AtDetails.clickEditMeta();
fillByPressKeyDown([["M"], ["Space"], ["1"], ["Shift", "Enter"], ["M"], ["Space"], ["2"], ["Enter"]]);
AtDetails.seeMeta("M 1");
AtDetails.seeMeta("M 2");
I.say("Add line to meta");
AtDetails.clickMeta();
fillByPressKeyDown([["Shift", "Enter"], ["3"], ["Enter"]]);
AtDetails.seeMeta("3");
AtDetails.dontSeeMeta("23");
I.say("Check that meta is saved correctly");
const resultWithMeta = await LabelStudio.serialize();
const regionWithMeta = getRectangleRegion(resultWithMeta);
assert.deepStrictEqual(regionWithMeta.meta?.text, ["M 1\nM 2\n3"]);
I.say("Remove meta");
AtDetails.clickMeta();
fillByPressKeyDown([["CommandOrControl", "a"], ["Backspace"], ["Enter"]]);
I.say("Check that meta is removed correctly");
const resultWithoutMeta = await LabelStudio.serialize();
const regionWithoutMeta = getRectangleRegion(resultWithoutMeta);
assert.deepStrictEqual(resultWithoutMeta[2].meta, undefined);
}).retry(3);
Scenario("Panels manipulations", async ({ I, LabelStudio, AtPanels }) => {
I.amOnPage("/");
LabelStudio.init({
config: `
`,
data: {
text: "Just a text",
},
annotations: [
{
id: "test",
result: [],
},
],
});
const AtOutlinerPanel = AtPanels.usePanel(AtPanels.PANEL.OUTLINER);
const AtDetailsPanel = AtPanels.usePanel(AtPanels.PANEL.DETAILS);
I.say("See panels at default positions");
AtOutlinerPanel.seePanelAttachedLeft();
AtDetailsPanel.seePanelAttachedRight();
I.say("They should be fully visible");
AtOutlinerPanel.seePanelBody();
AtDetailsPanel.seePanelBody();
I.say("and not collapsed");
AtOutlinerPanel.dontSeeExpandButton();
AtDetailsPanel.dontSeeExpandButton();
I.say("Collapse both panels");
AtOutlinerPanel.collapsePanel();
AtDetailsPanel.collapsePanel();
I.say("Make sure there is no body or collapse button");
AtOutlinerPanel.dontSeePanelBody();
AtDetailsPanel.dontSeePanelBody();
AtOutlinerPanel.dontSeeСollapseButton();
AtDetailsPanel.dontSeeСollapseButton();
AtOutlinerPanel.seeExpandButton();
AtDetailsPanel.seeExpandButton();
I.say("Try to move collapsed panel");
await AtOutlinerPanel.dragPanelBy(400, 0);
I.say("Check that nothing changes");
AtOutlinerPanel.seePanelAttachedLeft();
AtOutlinerPanel.dontSeePanelBody();
AtOutlinerPanel.dontSeeСollapseButton();
I.say("Expand both panels");
AtOutlinerPanel.expandPanel();
AtDetailsPanel.expandPanel();
I.say("Make sure that body and collapse appears");
AtOutlinerPanel.seePanelBody();
AtDetailsPanel.seePanelBody();
AtOutlinerPanel.seeСollapseButton();
AtDetailsPanel.seeСollapseButton();
AtOutlinerPanel.dontSeeExpandButton();
AtDetailsPanel.dontSeeExpandButton();
I.say("Try to drag one panel over another");
await AtOutlinerPanel.dragPanelToElement(AtDetailsPanel.locatePanel());
I.say("It should not affect other panel");
AtDetailsPanel.seePanelAttachedRight();
I.say("But it should detach dragged panel");
AtOutlinerPanel.seePanelDetached();
{
I.say("And x coordinate of panels should be equal due to limitation of moving panel through the border");
const panel1HeaderBbox = await AtOutlinerPanel.grabHeaderBbox();
const panel2HeaderBbox = await AtOutlinerPanel.grabHeaderBbox();
assert.strictEqual(panel1HeaderBbox.x, panel2HeaderBbox.x);
}
I.say("Drag panel somewhere to the center of the screen");
{
let panelBbox = await AtOutlinerPanel.grabPanelBbox();
const panelsContainerBbox = await AtPanels.grabPanelsContainerBbox();
const panelsContainerCenter = centerOfBbox(panelsContainerBbox);
await AtOutlinerPanel.dragPanelTo(panelsContainerCenter.x, panelsContainerCenter.y - panelBbox.height / 2);
I.say("Try to resize panel in all directions");
panelBbox = await AtOutlinerPanel.grabPanelBbox();
{
I.say("drag TopLeft corner");
await AtOutlinerPanel.dragResizerBy(-1, -2, AtOutlinerPanel.resizeTopLeft);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, -1);
assert.strictEqual(newPanelBbox.y - panelBbox.y, -2);
assert.strictEqual(newPanelBbox.width - panelBbox.width, 1);
assert.strictEqual(newPanelBbox.height - panelBbox.height, 2);
panelBbox = newPanelBbox;
}
{
I.say("drag TopRight corner");
await AtOutlinerPanel.dragResizerBy(-1, -2, AtOutlinerPanel.resizeTopRight);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, 0);
assert.strictEqual(newPanelBbox.y - panelBbox.y, -2);
assert.strictEqual(newPanelBbox.width - panelBbox.width, -1);
assert.strictEqual(newPanelBbox.height - panelBbox.height, 2);
panelBbox = newPanelBbox;
}
{
I.say("drag BottomRight corner");
await AtOutlinerPanel.dragResizerBy(3, 5, AtOutlinerPanel.resizeBottomRight);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, 0);
assert.strictEqual(newPanelBbox.y - panelBbox.y, 0);
assert.strictEqual(newPanelBbox.width - panelBbox.width, 3);
assert.strictEqual(newPanelBbox.height - panelBbox.height, 5);
panelBbox = newPanelBbox;
}
{
I.say("drag BottomLeft corner");
await AtOutlinerPanel.dragResizerBy(3, -5, AtOutlinerPanel.resizeBottomLeft);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, 3);
assert.strictEqual(newPanelBbox.y - panelBbox.y, 0);
assert.strictEqual(newPanelBbox.width - panelBbox.width, -3);
assert.strictEqual(newPanelBbox.height - panelBbox.height, -5);
panelBbox = newPanelBbox;
}
{
I.say("drag Top border");
await AtOutlinerPanel.dragResizerBy(10, -10, AtOutlinerPanel.resizeTop, 2);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, 0);
assert.strictEqual(newPanelBbox.y - panelBbox.y, -10);
assert.strictEqual(newPanelBbox.width - panelBbox.width, 0);
assert.strictEqual(newPanelBbox.height - panelBbox.height, 10);
panelBbox = newPanelBbox;
}
{
I.say("drag Right border");
await AtOutlinerPanel.dragResizerBy(100, -7, AtOutlinerPanel.resizeRight, 2);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, 0);
assert.strictEqual(newPanelBbox.y - panelBbox.y, 0);
assert.strictEqual(newPanelBbox.width - panelBbox.width, 100);
assert.strictEqual(newPanelBbox.height - panelBbox.height, 0);
panelBbox = newPanelBbox;
}
{
I.say("drag Bottom border");
await AtOutlinerPanel.dragResizerBy(11, 11, AtOutlinerPanel.resizeBottom);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, 0);
assert.strictEqual(newPanelBbox.y - panelBbox.y, 0);
assert.strictEqual(newPanelBbox.width - panelBbox.width, 0);
assert.strictEqual(newPanelBbox.height - panelBbox.height, 11);
panelBbox = newPanelBbox;
}
{
I.say("drag Left border");
await AtOutlinerPanel.dragResizerBy(7, -7, AtOutlinerPanel.resizeLeft);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert.strictEqual(newPanelBbox.x - panelBbox.x, 7);
assert.strictEqual(newPanelBbox.y - panelBbox.y, 0);
assert.strictEqual(newPanelBbox.width - panelBbox.width, -7);
assert.strictEqual(newPanelBbox.height - panelBbox.height, 0);
panelBbox = newPanelBbox;
}
{
I.say("Check maximal size restriction");
await AtOutlinerPanel.dragResizerBy(-1000, -1000, AtOutlinerPanel.resizeTopLeft);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert(newPanelBbox.x - panelBbox.x < 500);
assert(newPanelBbox.y - panelBbox.y < 500);
assert(newPanelBbox.width - panelBbox.width > -500);
assert(newPanelBbox.height - panelBbox.height > -500);
panelBbox = newPanelBbox;
}
{
I.say("Check minimal size restriction");
await AtOutlinerPanel.dragResizerBy(panelBbox.width, panelBbox.height + 50, AtOutlinerPanel.resizeTopLeft);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert(newPanelBbox.width > 100);
assert(newPanelBbox.height > 100);
assert(newPanelBbox.x < panelBbox.x + panelBbox.width - 100);
assert(newPanelBbox.y < panelBbox.y + panelBbox.height - 100);
panelBbox = newPanelBbox;
}
}
I.say("Move details to the left socket");
await AtDetailsPanel.dragPanelToLeftSocket();
AtDetailsPanel.seePanelAttachedLeft();
{
I.say("Move outliner to the right socket by moving to the left (check that there is some gap)");
const panelBbox = await AtOutlinerPanel.grabPanelBbox();
const panelContainerWidth = await AtOutlinerPanel.grabPanelsContainerBbox("width");
const shiftX = 50;
await AtOutlinerPanel.dragPanelTo(panelContainerWidth - panelBbox.width / 2 - shiftX, panelBbox.y);
AtOutlinerPanel.seePanelDetached();
await AtOutlinerPanel.dragResizerBy(shiftX, 0, AtOutlinerPanel.resizeRight);
AtOutlinerPanel.seePanelDetached();
await AtOutlinerPanel.dragPanelBy(-5, 0);
AtOutlinerPanel.seePanelAttachedRight();
}
I.say("Attached panels should be resizable");
{
const panelBbox = await AtOutlinerPanel.grabPanelBbox();
await AtOutlinerPanel.dragResizerBy(-10, 0, AtOutlinerPanel.resizeLeft);
const newPanelBbox = await AtOutlinerPanel.grabPanelBbox();
assert(newPanelBbox.width - panelBbox.width, 10);
}
{
const panelBbox = await AtDetailsPanel.grabPanelBbox();
await AtDetailsPanel.dragResizerBy(10, 0, AtOutlinerPanel.resizeRight);
const newPanelBbox = await AtDetailsPanel.grabPanelBbox();
assert(newPanelBbox.width - panelBbox.width, 10);
}
I.say("Collapse is still working");
AtOutlinerPanel.collapsePanel();
AtOutlinerPanel.dontSeePanelBody();
AtOutlinerPanel.dontSeeСollapseButton();
AtOutlinerPanel.seeExpandButton();
I.say("Drag panel somewhere to the center of the screen");
{
const panelBbox = await AtDetailsPanel.grabPanelBbox();
const panelsContainerBbox = await AtPanels.grabPanelsContainerBbox();
const panelsContainerCenter = centerOfBbox(panelsContainerBbox);
await AtDetailsPanel.dragPanelTo(panelsContainerCenter.x, panelsContainerCenter.y - panelBbox.height / 2);
AtDetailsPanel.seePanelDetached();
}
I.say("Collapse detached panel");
AtDetailsPanel.collapsePanel();
AtDetailsPanel.dontSeePanelBody();
AtDetailsPanel.dontSeeСollapseButton();
AtDetailsPanel.seeExpandButton();
I.say("Make sure that it is still movable");
await AtDetailsPanel.dragPanelToLeftSocket();
I.say("and attachable");
AtDetailsPanel.seePanelAttachedLeft();
I.say("and expandable");
AtDetailsPanel.expandPanel();
AtDetailsPanel.seePanelBody();
AtDetailsPanel.seeСollapseButton();
AtDetailsPanel.dontSeeExpandButton();
});