Add more end-to-end tests

This commit is contained in:
HarelM
2026-07-12 09:34:46 +03:00
parent 36073b2b1f
commit c22f7404e7
6 changed files with 142 additions and 15 deletions
+73 -7
View File
@@ -25,7 +25,19 @@ describe("layer editor", () => {
return id; return id;
} }
test.skip("expand/collapse", () => {}); test("expand/collapse", async () => {
const bgId = await createBackground();
await when.click("layer-list-item:background:" + bgId);
// Groups start expanded, so the "Layer" group's fields are on screen.
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 () => { test("id", async () => {
const bgId = await createBackground(); const bgId = await createBackground();
@@ -295,10 +307,43 @@ describe("layer editor", () => {
}); });
describe("paint", () => { describe("paint", () => {
test.skip("expand/collapse", () => {}); let id: string;
test.skip("color", () => {});
test.skip("pattern", () => {}); beforeEach(async () => {
test.skip("opacity", () => {}); 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", () => { describe("json-editor", () => {
@@ -318,8 +363,29 @@ describe("layer editor", () => {
await then(get.element(".cm-lint-marker-error")).shouldExist(); await then(get.element(".cm-lint-marker-error")).shouldExist();
}); });
test.skip("expand/collapse", () => {}); test("expand/collapse", async () => {
test.skip("modify", () => {}); 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);
// Append a property to the layer's JSON; the editor writes it back to the style.
await when.appendToJsonEditorLine('"background"', ',\n"minzoom": 5');
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [{ id: "background:" + bgId, type: "background", minzoom: 5 }],
});
});
test("parse error", async () => { test("parse error", async () => {
const bgId = await createBackground(); const bgId = await createBackground();
+17 -3
View File
@@ -97,7 +97,15 @@ describe("layers list", () => {
}); });
}); });
test.skip("modify", () => {}); test("modify", async () => {
const id = await when.modal.fillLayers({ type: "background" });
await when.click("layer-list-item:" + id);
await when.setValue("spec-field-input:background-opacity", "0.4");
await when.click("layer-editor.layer-id");
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [{ id, type: "background", paint: { "background-opacity": 0.4 } }],
});
});
}); });
describe("fill", () => { describe("fill", () => {
@@ -108,8 +116,14 @@ describe("layers list", () => {
}); });
}); });
// TODO: Change source test("change source", async () => {
test.skip("change source", () => {}); const id = await when.modal.fillLayers({ type: "fill", layer: "example" });
// The "both" style ships with an "example" and a "raster" source.
await when.changeLayerSource("raster");
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [{ id, type: "fill", source: "raster" }],
});
});
}); });
describe("line", () => { describe("line", () => {
+39
View File
@@ -128,6 +128,27 @@ export class MaputnikDriver {
await this.helper.get.element(".maputnik-layer-editor-group__button").nth(index).click(); await this.helper.get.element(".maputnik-layer-editor-group__button").nth(index).click();
}, },
/** Expands/collapses a layer-editor group by its title, e.g. "Paint properties". */
toggleGroupInLayerEditor: async (title: string) => {
await this.helper.when.click("layer-editor-group:" + title);
},
/** Adds one of the predefined public sources listed in the sources modal. */
addPublicSource: async (index = 0) => {
await this.helper.get.element(".maputnik-public-source-select").nth(index).click();
},
/**
* Picks a source for the selected layer from the source autocomplete.
* The autocomplete is a controlled (downshift) input, so the value has to be
* filled rather than typed key by key, then chosen from the filtered menu.
*/
changeLayerSource: async (sourceId: string) => {
const input = this.helper.get.elementByTestId("layer-editor.layer-source").locator("input");
await input.fill(sourceId);
await this.helper.get.element(".maputnik-autocomplete-menu-item").first().click();
},
appendTextInJsonEditor: async (text: string) => { appendTextInJsonEditor: async (text: string) => {
await this.helper.get.element(".cm-line").first().click(); await this.helper.get.element(".cm-line").first().click();
// Move to the very start of the document so the inserted text breaks the // Move to the very start of the document so the inserted text breaks the
@@ -199,6 +220,24 @@ export class MaputnikDriver {
await input.fill(value); await input.fill(value);
}, },
/** Sets a plain string spec field (e.g. a pattern), which has no dedicated input test id. */
setStringValue: async (fieldName: string, value: string) => {
const input = this.helper.get.elementByTestId("spec-field:" + fieldName).locator("input.maputnik-string");
await input.fill(value);
await input.blur();
},
/**
* Appends text to the end of the JSON editor line holding `lineText`.
* CodeMirror types over its own auto-inserted closing quotes/brackets, so a
* well-formed fragment stays well-formed.
*/
appendToJsonEditorLine: async (lineText: string, text: string) => {
await this.helper.when.clickByText(lineText);
await this.helper.when.typeKeys("{end}");
await this.helper.when.typeText(text);
},
exportCreateHtml: async () => { exportCreateHtml: async () => {
await this.helper.get.element(".maputnik-modal-export-buttons button").last().click(); await this.helper.get.element(".maputnik-modal-export-buttons button").last().click();
}, },
+11 -5
View File
@@ -91,7 +91,17 @@ describe("modals", () => {
).shouldEqual(before - 1); ).shouldEqual(before - 1);
}); });
test.skip("public source", () => {}); test("public source", async () => {
await when.addPublicSource();
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
sources: {
openmaptiles: {
type: "vector",
url: `https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=${tokens.openmaptiles}`,
},
},
});
});
test("add new source", async () => { test("add new source", async () => {
const sourceId = "n1z2v3r"; const sourceId = "n1z2v3r";
@@ -327,10 +337,6 @@ describe("modals", () => {
}); });
}); });
describe("sources placeholder", () => {
test.skip("toggle", () => {});
});
describe("global state", () => { describe("global state", () => {
beforeEach(async () => { beforeEach(async () => {
await when.click("nav:global-state"); await when.click("nav:global-state");
+1
View File
@@ -145,6 +145,7 @@ async function typeSequence(page: Page, text: string): Promise<void> {
del: "Delete", del: "Delete",
tab: "Tab", tab: "Tab",
home: "Home", home: "Home",
end: "End",
rightarrow: "ArrowRight", rightarrow: "ArrowRight",
}; };
+1
View File
@@ -230,6 +230,7 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
)} )}
/> />
{this.props.layer.type !== "background" && <FieldSource {this.props.layer.type !== "background" && <FieldSource
wdKey="layer-editor.layer-source"
error={errorData.source} error={errorData.source}
sourceIds={Object.keys(this.props.sources!)} sourceIds={Object.keys(this.props.sources!)}
value={this.props.layer.source} value={this.props.layer.source}