mirror of
https://github.com/maputnik/editor.git
synced 2026-07-14 09:57:29 +00:00
f14eeae38b
## Launch Checklist This PR increases coverage by adding unit tests to lib folde, replace the skipped end to end placeholder with actual tests and adds more end to end tests. This was mostly done by AI (Claude opus 4.8) and I reviewed it and requested changes where needed. - [x] Briefly describe the changes in this PR. - [x] Link to related issues. - [x] Include before/after visuals or gifs if this PR includes visual changes. - [x] Write tests for all new functionality. - [x] Add an entry to `CHANGELOG.md` under the `## main` section. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
605 lines
21 KiB
TypeScript
605 lines
21 KiB
TypeScript
import { v1 as uuid } from "uuid";
|
|
import { beforeEach, describe, test } from "./utils/fixtures";
|
|
import { MaputnikDriver } from "./maputnik-driver";
|
|
|
|
describe("layer editor", () => {
|
|
const { given, get, when, then } = new MaputnikDriver();
|
|
|
|
beforeEach(async () => {
|
|
await given.setupMockBackedResponses();
|
|
await when.setStyle("both");
|
|
await when.modal.open();
|
|
});
|
|
|
|
async function createBackground() {
|
|
const id = uuid();
|
|
|
|
await when.selectWithin("add-layer.layer-type", "background");
|
|
await when.setValue("add-layer.layer-id.input", "background:" + id);
|
|
|
|
await when.click("add-layer");
|
|
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + id, type: "background" }],
|
|
});
|
|
return id;
|
|
}
|
|
|
|
test("expand/collapse", async () => {
|
|
const bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
|
|
await then(get.elementByTestId("layer-editor.layer-id.input")).shouldBeVisible();
|
|
|
|
await when.toggleGroupInLayerEditor("Layer");
|
|
await then(get.elementByTestId("layer-editor.layer-id.input")).shouldNotBeVisible();
|
|
|
|
await when.toggleGroupInLayerEditor("Layer");
|
|
await then(get.elementByTestId("layer-editor.layer-id.input")).shouldBeVisible();
|
|
});
|
|
|
|
test("id", async () => {
|
|
const bgId = await createBackground();
|
|
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
|
|
const id = uuid();
|
|
await when.setValue("layer-editor.layer-id.input", "foobar:" + id);
|
|
await when.click("min-zoom");
|
|
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "foobar:" + id, type: "background" }],
|
|
});
|
|
});
|
|
|
|
describe("source", () => {
|
|
test("should show error when the source is invalid", async () => {
|
|
await when.modal.fillLayers({
|
|
type: "circle",
|
|
layer: "invalid",
|
|
});
|
|
await then(
|
|
get.element(".maputnik-input-block--error .maputnik-input-block-label")
|
|
).shouldHaveCss("color", "rgb(207, 74, 74)");
|
|
});
|
|
});
|
|
|
|
describe("min-zoom", () => {
|
|
let bgId: string;
|
|
|
|
beforeEach(async () => {
|
|
bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
await when.setValue("min-zoom.input-text", "1");
|
|
await when.click("layer-editor.layer-id");
|
|
});
|
|
|
|
test("should update min-zoom in local storage", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background", minzoom: 1 }],
|
|
});
|
|
});
|
|
|
|
test("when clicking next layer should update style on local storage", async () => {
|
|
await when.type("min-zoom.input-text", "{backspace}");
|
|
await when.click("max-zoom.input-text");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background", minzoom: 1 }],
|
|
});
|
|
});
|
|
|
|
test("the range slider adjusts min-zoom", async () => {
|
|
await when.focus("min-zoom.input-range");
|
|
await when.typeKeys("{rightarrow}");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background", minzoom: 2 }],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("max-zoom", () => {
|
|
let bgId: string;
|
|
|
|
beforeEach(async () => {
|
|
bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
await when.setValue("max-zoom.input-text", "1");
|
|
await when.click("layer-editor.layer-id");
|
|
});
|
|
|
|
test("should update style in local storage", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background", maxzoom: 1 }],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("comments", () => {
|
|
let bgId: string;
|
|
const comment = "42";
|
|
|
|
beforeEach(async () => {
|
|
bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
await when.setValue("layer-comment.input", comment);
|
|
await when.click("layer-editor.layer-id");
|
|
});
|
|
|
|
test("should update style in local storage", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [
|
|
{
|
|
id: "background:" + bgId,
|
|
type: "background",
|
|
metadata: { "maputnik:comment": comment },
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
describe("when unsetting", () => {
|
|
beforeEach(async () => {
|
|
await when.clear("layer-comment.input");
|
|
await when.click("min-zoom.input-text");
|
|
});
|
|
|
|
test("should update style in local storage", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background" }],
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("color", () => {
|
|
let bgId: string;
|
|
beforeEach(async () => {
|
|
bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
await when.click("spec-field:background-color");
|
|
});
|
|
|
|
test("should update style in local storage", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background" }],
|
|
});
|
|
});
|
|
|
|
test("typing a hex value updates the paint color", async () => {
|
|
await when.setColorValue("background-color", "#ff0000");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background", paint: { "background-color": "#ff0000" } }],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("opacity", () => {
|
|
let bgId: string;
|
|
beforeEach(async () => {
|
|
bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
await when.type("spec-field-input:background-opacity", "0.");
|
|
});
|
|
|
|
test("should keep '.' in the input field", async () => {
|
|
await then(get.elementByTestId("spec-field-input:background-opacity")).shouldHaveValue("0.");
|
|
});
|
|
|
|
test("should revert to a valid value when focus out", async () => {
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
await then(get.elementByTestId("spec-field-input:background-opacity")).shouldHaveValue("0");
|
|
});
|
|
});
|
|
|
|
describe("filter", () => {
|
|
let id: string;
|
|
|
|
beforeEach(async () => {
|
|
id = await when.modal.fillLayers({ type: "fill", layer: "example" });
|
|
await when.addFilter();
|
|
});
|
|
|
|
test("should add a filter item", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, type: "fill", source: "example", filter: ["all", ["==", "name", ""]] }],
|
|
});
|
|
});
|
|
|
|
test("should change the filter operator", async () => {
|
|
await when.selectFilterOperator("!=");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, filter: ["all", ["!=", "name", ""]] }],
|
|
});
|
|
});
|
|
|
|
test("should extend the compound filter with a second item", async () => {
|
|
await when.addFilter();
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, filter: ["all", ["==", "name", ""], ["==", "name", ""]] }],
|
|
});
|
|
});
|
|
|
|
test("should change the combining operator", async () => {
|
|
await when.selectFilterCombiningOperator("any");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, filter: ["any", ["==", "name", ""]] }],
|
|
});
|
|
});
|
|
|
|
test("should delete a filter item", async () => {
|
|
await when.addFilter();
|
|
await when.deleteFilterItem();
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, filter: ["all", ["==", "name", ""]] }],
|
|
});
|
|
});
|
|
|
|
describe("when converted to an expression", () => {
|
|
beforeEach(async () => {
|
|
await when.convertFilterToExpression();
|
|
});
|
|
|
|
test("should migrate the filter to an expression", async () => {
|
|
// A single-item "all" collapses to the bare comparison when migrated.
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, filter: ["==", ["get", "name"], ""] }],
|
|
});
|
|
});
|
|
|
|
test("should restore the default filter when the expression is deleted", async () => {
|
|
await when.deleteFilterExpression();
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, filter: ["all"] }],
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("functions", () => {
|
|
let id: string;
|
|
|
|
describe("zoom function", () => {
|
|
beforeEach(async () => {
|
|
id = await when.modal.fillLayers({ type: "circle", layer: "example" });
|
|
await when.makeZoomFunction("circle-radius");
|
|
});
|
|
|
|
test("should convert the property to a zoom function", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [
|
|
{ id, type: "circle", source: "example", paint: { "circle-radius": { stops: [[6, 5], [10, 5]] } } },
|
|
],
|
|
});
|
|
});
|
|
|
|
test("should add a stop", async () => {
|
|
await when.addFunctionStop("circle-radius");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-radius": { stops: [[6, 5], [10, 5], [11, 5]] } } }],
|
|
});
|
|
});
|
|
|
|
test("should delete the first stop", async () => {
|
|
// A function needs more than two stops, otherwise deleting one collapses
|
|
// it back into a plain value.
|
|
await when.addFunctionStop("circle-radius");
|
|
await when.deleteFunctionStop("circle-radius");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-radius": { stops: [[10, 5], [11, 5]] } } }],
|
|
});
|
|
});
|
|
|
|
test("should set the base", async () => {
|
|
await when.setFunctionBase("circle-radius", "2");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-radius": { base: 2, stops: [[6, 5], [10, 5]] } } }],
|
|
});
|
|
});
|
|
|
|
test("should edit the zoom of a stop", async () => {
|
|
await when.setFunctionStopValue("circle-radius", "Zoom", 0, "3");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-radius": { stops: [[3, 5], [10, 5]] } } }],
|
|
});
|
|
});
|
|
|
|
test("should edit the output value of a stop", async () => {
|
|
await when.setFunctionStopValue("circle-radius", "Output value", 0, "9");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-radius": { stops: [[6, 9], [10, 5]] } } }],
|
|
});
|
|
});
|
|
|
|
test("should convert to an expression", async () => {
|
|
await when.makeExpression("circle-radius");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-radius": ["interpolate", ["linear"], ["zoom"], 6, 5, 10, 5] } }],
|
|
});
|
|
});
|
|
|
|
describe("when converted to a data function", () => {
|
|
beforeEach(async () => {
|
|
// Any non-interpolate scale turns the zoom function into a data one.
|
|
await when.selectFunctionType("circle-radius", "categorical");
|
|
});
|
|
|
|
test("should carry the stops over as zoom/value pairs", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [
|
|
{
|
|
id,
|
|
paint: {
|
|
"circle-radius": {
|
|
property: "",
|
|
type: "exponential",
|
|
stops: [[{ zoom: 6, value: 0 }, 5], [{ zoom: 10, value: 0 }, 5]],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
test("should convert back to a zoom function", async () => {
|
|
await when.selectFunctionType("circle-radius", "interpolate");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-radius": { stops: [[6, 5], [10, 5]] } } }],
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("data function", () => {
|
|
beforeEach(async () => {
|
|
id = await when.modal.fillLayers({ type: "circle", layer: "example" });
|
|
await when.setValue("spec-field-input:circle-blur", "1");
|
|
await when.makeDataFunction("circle-blur");
|
|
});
|
|
|
|
test("should convert the property to a data function", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [
|
|
{
|
|
id,
|
|
type: "circle",
|
|
source: "example",
|
|
paint: {
|
|
"circle-blur": {
|
|
property: "",
|
|
type: "exponential",
|
|
stops: [[{ zoom: 6, value: 0 }, 1], [{ zoom: 10, value: 0 }, 1]],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
test("should add a stop", async () => {
|
|
await when.addFunctionStop("circle-blur");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [
|
|
{
|
|
id,
|
|
paint: {
|
|
"circle-blur": {
|
|
stops: [[{ zoom: 6, value: 0 }, 1], [{ zoom: 10, value: 0 }, 1], [{ zoom: 11, value: 0 }, 1]],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
test("should delete the first stop", async () => {
|
|
await when.addFunctionStop("circle-blur");
|
|
await when.deleteFunctionStop("circle-blur");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [
|
|
{
|
|
id,
|
|
paint: {
|
|
"circle-blur": {
|
|
stops: [[{ zoom: 10, value: 0 }, 1], [{ zoom: 11, value: 0 }, 1]],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
test("should set the property", async () => {
|
|
await when.setFunctionProperty("circle-blur", "myprop");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-blur": { property: "myprop" } } }],
|
|
});
|
|
});
|
|
|
|
test("should set the default", async () => {
|
|
await when.setFunctionDefault("circle-blur", "0.5");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-blur": { default: 0.5 } } }],
|
|
});
|
|
});
|
|
|
|
test("should edit the input value of a stop", async () => {
|
|
await when.setFunctionStopValue("circle-blur", "Input value", 0, "7");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [
|
|
{
|
|
id,
|
|
paint: {
|
|
"circle-blur": {
|
|
stops: [[{ zoom: 6, value: 7 }, 1], [{ zoom: 10, value: 0 }, 1]],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
test("should change the function type", async () => {
|
|
await when.selectFunctionType("circle-blur", "categorical");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-blur": { type: "categorical" } } }],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("expression", () => {
|
|
beforeEach(async () => {
|
|
id = await when.modal.fillLayers({ type: "circle", layer: "example" });
|
|
await when.setValue("spec-field-input:circle-blur", "1");
|
|
await when.makeExpression("circle-blur");
|
|
});
|
|
|
|
test("should wrap the property value in a literal expression", async () => {
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-blur": ["literal", 1] } }],
|
|
});
|
|
});
|
|
|
|
test("should restore the plain value when reverted", async () => {
|
|
await when.undoExpression("circle-blur");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-blur": 1 } }],
|
|
});
|
|
});
|
|
|
|
test("should fall back to the spec default when deleted", async () => {
|
|
await when.deleteExpression("circle-blur");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, paint: { "circle-blur": 0 } }],
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("layout", () => {
|
|
test("text-font", async () => {
|
|
await when.setStyle("font");
|
|
await when.collapseGroupInLayerEditor();
|
|
await when.collapseGroupInLayerEditor(1);
|
|
await when.collapseGroupInLayerEditor(2);
|
|
await when.clickWithin("spec-field:text-font", ".maputnik-autocomplete input");
|
|
await then(get.element(".maputnik-autocomplete-menu-item")).shouldBeVisible();
|
|
await then(get.element(".maputnik-autocomplete-menu-item")).shouldHaveLength(3);
|
|
});
|
|
});
|
|
|
|
describe("paint", () => {
|
|
let id: string;
|
|
|
|
beforeEach(async () => {
|
|
id = await when.modal.fillLayers({ type: "fill", layer: "example" });
|
|
});
|
|
|
|
test("expand/collapse", async () => {
|
|
await then(get.elementByTestId("spec-field:fill-color")).shouldBeVisible();
|
|
|
|
await when.toggleGroupInLayerEditor("Paint properties");
|
|
await then(get.elementByTestId("spec-field:fill-color")).shouldNotBeVisible();
|
|
|
|
await when.toggleGroupInLayerEditor("Paint properties");
|
|
await then(get.elementByTestId("spec-field:fill-color")).shouldBeVisible();
|
|
});
|
|
|
|
test("color", async () => {
|
|
await when.setColorValue("fill-color", "#ff0000");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, type: "fill", source: "example", paint: { "fill-color": "#ff0000" } }],
|
|
});
|
|
});
|
|
|
|
test("pattern", async () => {
|
|
await when.setStringValue("fill-pattern", "some-pattern");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, type: "fill", source: "example", paint: { "fill-pattern": "some-pattern" } }],
|
|
});
|
|
});
|
|
|
|
test("opacity", async () => {
|
|
await when.setValue("spec-field-input:fill-opacity", "0.4");
|
|
await when.click("layer-editor.layer-id");
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, type: "fill", source: "example", paint: { "fill-opacity": 0.4 } }],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("json-editor", () => {
|
|
test("add", async () => {
|
|
const id = await when.modal.fillLayers({
|
|
type: "circle",
|
|
layer: "example",
|
|
});
|
|
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id, type: "circle", source: "example" }],
|
|
});
|
|
|
|
await when.clickByText('"source"');
|
|
await when.typeKeys('"');
|
|
|
|
await then(get.element(".cm-lint-marker-error")).shouldExist();
|
|
});
|
|
|
|
test("expand/collapse", async () => {
|
|
const bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
|
|
await then(get.element(".cm-content")).shouldBeVisible();
|
|
|
|
await when.toggleGroupInLayerEditor("JSON Editor");
|
|
await then(get.element(".cm-content")).shouldNotBeVisible();
|
|
|
|
await when.toggleGroupInLayerEditor("JSON Editor");
|
|
await then(get.element(".cm-content")).shouldBeVisible();
|
|
});
|
|
|
|
test("modify", async () => {
|
|
const bgId = await createBackground();
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
|
|
await when.appendToJsonEditorLine('"background"', ',\n"minzoom": 5');
|
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
|
layers: [{ id: "background:" + bgId, type: "background", minzoom: 5 }],
|
|
});
|
|
});
|
|
|
|
test("parse error", async () => {
|
|
const bgId = await createBackground();
|
|
|
|
await when.click("layer-list-item:background:" + bgId);
|
|
await when.collapseGroupInLayerEditor();
|
|
await when.collapseGroupInLayerEditor(1);
|
|
await then(get.element(".cm-lint-marker-error")).shouldNotExist();
|
|
|
|
// Inject an invalid token (CodeMirror auto-closes brackets/quotes, so a
|
|
// bare word reliably breaks the JSON) and expect a lint error.
|
|
await when.appendTextInJsonEditor("zzz");
|
|
await then(get.element(".cm-lint-marker-error")).shouldExist();
|
|
});
|
|
});
|
|
|
|
describe("sticky header", () => {
|
|
test("should keep layer header visible when scrolling properties", async () => {
|
|
// Setup: Create a layer with many properties (e.g. symbol layer)
|
|
await when.modal.fillLayers({
|
|
type: "symbol",
|
|
layer: "example",
|
|
});
|
|
|
|
await when.wait(500);
|
|
const header = get.elementByTestId("layer-editor.header");
|
|
await then(header).shouldBeVisible();
|
|
|
|
await when.scrollToBottom(get.element(".maputnik-scroll-container"));
|
|
await when.wait(200);
|
|
|
|
await then(header).shouldBeVisible();
|
|
await then(get.elementByTestId("skip-target-layer-editor")).shouldBeVisible();
|
|
});
|
|
});
|
|
});
|