const { saveDraftLocally, getLocallySavedDraft } = require("./helpers");
const assert = require("assert");
Feature("Unfinished polygons");
const IMAGE =
"https://htx-pub.s3.us-east-1.amazonaws.com/examples/images/nick-owuor-astro-nic-visuals-wDifg5xc9Z4-unsplash.jpg";
const CONFIG = `
`;
const CONFIG_MULTIPLE = `
`;
Scenario("Drafts for unfinished polygons", async ({ I, LabelStudio, AtLabels, AtImageView }) => {
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
params: {
onSubmitDraft: saveDraftLocally,
},
});
LabelStudio.waitForObjectsReady();
await AtImageView.lookForStage();
I.say("start drawing polygon without finishing it");
AtLabels.clickLabel("Hello");
AtImageView.drawByClickingPoints([
[50, 50],
[100, 50],
[100, 80],
]);
I.say("wait until autosave");
I.waitForFunction(() => !!window.LSDraft, 0.5);
I.say("check result");
const draft = await I.executeScript(getLocallySavedDraft);
assert.strictEqual(draft[0].value.points.length, 3);
assert.strictEqual(draft[0].value.closed, false);
});
Scenario("Saving polygon drawing steps to history", async ({ I, LabelStudio, AtLabels, AtImageView }) => {
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
});
LabelStudio.waitForObjectsReady();
await AtImageView.lookForStage();
I.say("put one point of polygon");
AtLabels.clickLabel("Hello");
AtImageView.drawByClick(50, 50);
I.say("check current history size");
let historyStepsCount = await I.executeScript(() => window.Htx.annotationStore.selected.history.history.length);
assert.strictEqual(historyStepsCount, 2);
I.say("try to draw some more points and close polygon");
AtImageView.drawByClick(100, 50);
AtImageView.drawByClick(125, 100);
AtImageView.drawByClick(50, 50);
I.say("check current history size and result");
historyStepsCount = await I.executeScript(() => window.Htx.annotationStore.selected.history.history.length);
assert.strictEqual(historyStepsCount, 5);
let result = await LabelStudio.serialize();
assert.strictEqual(result[0].value.points.length, 3);
assert.strictEqual(result[0].value.closed, true);
I.say("try to undo closing and 2 last points");
I.click("button[aria-label=Undo]");
I.click("button[aria-label=Undo]");
I.click("button[aria-label=Undo]");
I.say("check current history index and result");
historyStepsCount = await I.executeScript(() => window.Htx.annotationStore.selected.history.undoIdx);
assert.strictEqual(historyStepsCount, 1);
result = await LabelStudio.serialize();
assert.strictEqual(result[0].value.points.length, 1);
assert.strictEqual(result[0].value.closed, false);
});
Scenario("Init an annotation with old format of closed polygon result", async ({ I, LabelStudio, AtImageView }) => {
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
annotations: [
{
id: "test",
result: [
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
points: [
[22.38442822384428, 27.042801556420233],
[77.61557177615572, 24.90272373540856],
[48.90510948905109, 76.07003891050584],
],
polygonlabels: ["Hello"],
},
id: "tNe7Bjmydb",
from_name: "tag",
to_name: "img",
type: "polygonlabels",
origin: "manual",
},
],
},
],
});
LabelStudio.waitForObjectsReady();
const result = await LabelStudio.serialize();
assert.strictEqual(result[0].value.points.length, 3);
assert.strictEqual(result[0].value.closed, true);
});
Scenario("Init an annotation with result of new format of polygon results", async ({ I, LabelStudio, AtImageView }) => {
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
annotations: [
{
id: "test",
result: [
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
points: [
[40, 40],
[50, 40],
[50, 50],
[40, 50],
],
closed: true,
polygonlabels: ["World"],
},
id: "tNe7Bjmydb_2",
from_name: "tag",
to_name: "img",
type: "polygonlabels",
origin: "manual",
},
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
points: [
[10, 10],
[30, 10],
[20, 20],
],
closed: false,
polygonlabels: ["Hello"],
},
id: "tNe7Bjmydb",
from_name: "tag",
to_name: "img",
type: "polygonlabels",
origin: "manual",
},
],
},
],
});
LabelStudio.waitForObjectsReady();
I.say("check loaded regions");
let result = await LabelStudio.serialize();
assert.strictEqual(result.length, 2);
assert.strictEqual(result[0].value.points.length, 4);
assert.strictEqual(result[0].value.closed, true);
assert.strictEqual(result[1].value.points.length, 3);
assert.strictEqual(result[1].value.closed, false);
I.say("try to continue drawing loaded unfinished region");
await AtImageView.lookForStage();
const canvasSize = await AtImageView.getCanvasSize();
AtImageView.drawByClick(canvasSize.width * 0.1, canvasSize.height * 0.4);
result = await LabelStudio.serialize();
assert.strictEqual(result[1].value.points.length, 4);
assert.strictEqual(result[1].value.closed, false);
I.say("try to close loaded region");
AtImageView.drawByClick(canvasSize.width * 0.1, canvasSize.height * 0.1);
result = await LabelStudio.serialize();
assert.strictEqual(result[1].value.points.length, 4);
assert.strictEqual(result[1].value.closed, true);
// I.say("check that it is possible to go back throught history");
// I.pressKey(['CommandOrControl', 'Z']);
// result = await LabelStudio.serialize();
// assert.strictEqual(result[1].value.points.length, 4);
// assert.strictEqual(result[1].value.closed, false);
//
// I.say("check that it is possible to close this region again");
// AtImageView.drawByClick(canvasSize.width * .10, canvasSize.height * .10);
// result = await LabelStudio.serialize();
// assert.strictEqual(result[1].value.points.length, 4);
// assert.strictEqual(result[1].value.closed, true);
});
Scenario("Removing a polygon by going back through history", async ({ I, LabelStudio, AtLabels, AtImageView }) => {
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
params: {
onSubmitDraft: saveDraftLocally,
},
});
LabelStudio.waitForObjectsReady();
await AtImageView.lookForStage();
I.say("start drawing polygon");
AtLabels.clickLabel("Hello");
AtImageView.drawByClickingPoints([
[50, 50],
[100, 50],
]);
I.say("revert all changes and creating of the region");
I.pressKey(["CommandOrControl", "Z"]);
I.pressKey(["CommandOrControl", "Z"]);
I.say("polygon should disappear and polygon tool should be switched of");
let result = await LabelStudio.serialize();
assert.strictEqual(result.length, 0);
I.say("try to draw after that");
AtImageView.drawByClickingPoints([
[50, 50],
[100, 50],
]);
I.say("check if it was possible to do this (it shouldn't)");
result = await LabelStudio.serialize();
assert.strictEqual(result.length, 0);
I.say("check if there were any errors");
// The potential errors should be caught by `errorsCollector` plugin
});
Scenario("Continue annotating after closing region from draft", async ({ I, LabelStudio, AtLabels, AtImageView }) => {
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
annotations: [
{
id: "test",
result: [
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
points: [
[10, 10],
[30, 10],
[20, 20],
],
closed: false,
polygonlabels: ["Hello"],
},
id: "tNe7Bjmydb",
from_name: "tag",
to_name: "img",
type: "polygonlabels",
origin: "manual",
},
],
},
],
});
LabelStudio.waitForObjectsReady();
await AtImageView.lookForStage();
const canvasSize = await AtImageView.getCanvasSize();
I.say("close loaded region");
AtImageView.drawByClick(canvasSize.width * 0.1, canvasSize.height * 0.1);
I.say("try to create another region");
AtLabels.clickLabel("World");
AtImageView.drawByClickingPoints([
[canvasSize.width * 0.4, canvasSize.height * 0.4],
[canvasSize.width * 0.5, canvasSize.height * 0.4],
[canvasSize.width * 0.5, canvasSize.height * 0.5],
[canvasSize.width * 0.4, canvasSize.height * 0.5],
[canvasSize.width * 0.4, canvasSize.height * 0.4],
]);
const result = await LabelStudio.serialize();
assert.strictEqual(result.length, 2);
assert.strictEqual(result[1].value.points.length, 4);
assert.strictEqual(result[1].value.closed, true);
});
Scenario("Change label on unfinished polygons", async ({ I, LabelStudio, AtLabels, AtImageView }) => {
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
params: {
onSubmitDraft: saveDraftLocally,
},
});
LabelStudio.waitForObjectsReady();
await AtImageView.lookForStage();
I.say("start drawing polygon without finishing it");
AtLabels.clickLabel("Hello");
AtImageView.drawByClickingPoints([
[50, 50],
[100, 50],
[100, 80],
]);
AtLabels.clickLabel("World");
I.say("wait until autosave");
I.waitForFunction(() => !!window.LSDraft, 0.5);
I.say("check result");
const draft = await I.executeScript(getLocallySavedDraft);
assert.strictEqual(draft[0].value.polygonlabels[0], "World");
});
const selectedLabelsVariants = new DataTable(["labels"]);
selectedLabelsVariants.add([["Label 1"]]);
selectedLabelsVariants.add([["Label 2", "Label 3"]]);
Data(selectedLabelsVariants).Scenario(
"Indicate selected labels",
async ({ I, LabelStudio, AtLabels, AtImageView, current }) => {
const { labels } = current;
I.amOnPage("/");
LabelStudio.init({
config: CONFIG_MULTIPLE,
data: {
image: IMAGE,
},
annotations: [
{
id: "test",
result: [
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
points: [
[10, 10],
[30, 10],
[20, 20],
],
closed: false,
polygonlabels: labels,
},
id: "tNe7Bjmydb",
from_name: "tag",
to_name: "img",
type: "polygonlabels",
origin: "manual",
},
],
},
],
});
LabelStudio.waitForObjectsReady();
await AtImageView.lookForStage();
const canvasSize = await AtImageView.getCanvasSize();
I.say("check if we see an indication of selected labels after resuming from draft");
for (const label of labels) {
AtLabels.seeSelectedLabel(label);
}
I.say("close loaded region");
AtImageView.drawByClick(canvasSize.width * 0.1, canvasSize.height * 0.1);
I.say("check that we do not see an indication of selected after region completion");
for (const label of labels) {
AtLabels.dontSeeSelectedLabel(label);
}
I.say("check if we see an indication of selected labels after going back through the history");
I.pressKey(["CommandOrControl", "Z"]);
for (const label of labels) {
AtLabels.seeSelectedLabel(label);
}
},
);
const selectedPolygonAfterCreatingVariants = new DataTable(["shouldSelect", "description"]);
selectedPolygonAfterCreatingVariants.add([false, "Without set setting"]);
selectedPolygonAfterCreatingVariants.add([true, "With set setting"]);
Data(selectedPolygonAfterCreatingVariants).Scenario(
"Select polygon after creating from unfinished draft",
async ({ I, LabelStudio, AtImageView, AtOutliner, AtSettings, current }) => {
const { shouldSelect, description } = current;
I.say(description);
I.amOnPage("/");
LabelStudio.init({
config: CONFIG,
data: {
image: IMAGE,
},
annotations: [
{
id: "test",
result: [
{
original_width: 2242,
original_height: 2802,
image_rotation: 0,
value: {
points: [
[10, 10],
[30, 10],
[20, 20],
],
closed: false,
polygonlabels: ["Hello"],
},
id: "tNe7Bjmydb",
from_name: "tag",
to_name: "img",
type: "polygonlabels",
origin: "manual",
},
],
},
],
});
if (shouldSelect) {
AtSettings.open();
AtSettings.setGeneralSettings({
[AtSettings.GENERAL_SETTINGS.AUTO_SELECT_REGION]: shouldSelect,
});
AtSettings.close();
}
LabelStudio.waitForObjectsReady();
await AtImageView.lookForStage();
const canvasSize = await AtImageView.getCanvasSize();
I.waitTicks(2);
I.say("close loaded region");
AtImageView.drawByClick(canvasSize.width * 0.1, canvasSize.height * 0.1);
I.say(`check that region ${shouldSelect ? "is" : "is not"} selected`);
if (shouldSelect) {
AtOutliner.seeSelectedRegion();
} else {
AtOutliner.dontSeeSelectedRegion();
}
I.say("unselect regions");
I.pressKey("u");
AtOutliner.dontSeeSelectedRegion();
I.say("go back through the history");
I.pressKey(["CommandOrControl", "Z"]);
I.waitTicks(2);
AtOutliner.dontSeeSelectedRegion();
I.say("repeat creation and checking");
AtImageView.drawByClick(canvasSize.width * 0.1, canvasSize.height * 0.1);
if (shouldSelect) {
AtOutliner.seeSelectedRegion();
} else {
AtOutliner.dontSeeSelectedRegion();
}
},
);