diff --git a/assets/src/components/Snapping.js b/assets/src/components/Snapping.js
index 48c69a63c0..e4d72dc1d0 100644
--- a/assets/src/components/Snapping.js
+++ b/assets/src/components/Snapping.js
@@ -26,23 +26,12 @@ export default class Snapping extends HTMLElement {
-
-
-
-
+
${mainLizmap.snapping.active ?
html`
@@ -91,8 +80,7 @@ export default class Snapping extends HTMLElement {
},
[
'snapping.config',
- 'snapping.active',
- 'snapping.refreshable'
+ 'snapping.active'
]
);
}
diff --git a/assets/src/modules/Snapping.js b/assets/src/modules/Snapping.js
index 4593cb0d68..17e37c6796 100644
--- a/assets/src/modules/Snapping.js
+++ b/assets/src/modules/Snapping.js
@@ -5,11 +5,16 @@
* @license MPL-2.0
*/
-import { mainEventDispatcher } from '../modules/Globals.js';
+import { mainLizmap, mainEventDispatcher } from '../modules/Globals.js';
import Edition from './Edition.js';
import { MapLayerLoadStatus, MapRootState } from './state/MapLayer.js';
import { TreeRootState } from './state/LayerTree.js';
-import WFS from './WFS.js';
+
+import { Snap } from 'ol/interaction.js';
+import { Vector as VectorSource } from 'ol/source.js';
+import { Vector as VectorLayer } from 'ol/layer.js';
+import { Circle, Fill, Stroke, Style } from 'ol/style.js';
+import GeoJSON from 'ol/format/GeoJSON.js';
/**
* @class
@@ -32,7 +37,6 @@ export default class Snapping {
this._lizmap3 = lizmap3;
this._active = false;
- this._snapLayersRefreshable = false;
this._maxFeatures = 1000;
this._restrictToMapExtent = true;
@@ -42,36 +46,38 @@ export default class Snapping {
this._snapLayers = [];
this._snapOnStart = false;
this._pendingMapReadyListener = null;
- this._wfsErrorNotified = false;
-
- // Create layer to store snap features
- const snapLayer = new OpenLayers.Layer.Vector('snaplayer', {
- visibility: false,
- styleMap: new OpenLayers.StyleMap({
- pointRadius: 2,
- fill: false,
- stroke: false,
- strokeWidth: 3,
- strokeColor: 'red',
- strokeOpacity: 0.8
+
+ // Create OL6 snap source and layer with a subtle solid style
+ this._snapSource = new VectorSource();
+ this._snapLayer = new VectorLayer({
+ source: this._snapSource,
+ visible: false,
+ style: new Style({
+ stroke: new Stroke({
+ color: 'rgba(255, 140, 0, 0.7)',
+ width: 1.5
+ }),
+ fill: new Fill({
+ color: 'rgba(255, 140, 0, 0.05)'
+ }),
+ image: new Circle({
+ radius: 4,
+ fill: new Fill({ color: 'rgba(255, 140, 0, 0.4)' }),
+ stroke: new Stroke({ color: 'rgba(255, 140, 0, 0.8)', width: 1 })
+ })
})
});
+ this._snapLayer.setProperties({ name: 'snaplayer' });
- this._lizmap3.map.addLayer(snapLayer);
- this._snapLayer = snapLayer;
+ // Will be added to map once mainLizmap.map is ready
+ this._snapInteraction = null;
+ this._mapReady = false;
- const snapControl = new OpenLayers.Control.Snapping({
- layer: this._edition.editLayer,
- targets: [{
- layer: snapLayer
- }]
- });
- this._lizmap3.map.addControls([snapControl]);
- this._lizmap3.controls['snapControl'] = snapControl;
-
- this._setSnapLayersRefreshable = () => {
- if(this._active){
- this.snapLayersRefreshable = true;
+ // OL6 Snap source feeds off in-memory features; reload them after the
+ // map view moves so off-extent geometry comes into snap range.
+ this._refreshSnapDataOnMoveEnd = () => {
+ if (this._active) {
+ this.getSnappingData();
}
}
@@ -87,7 +93,6 @@ export default class Snapping {
config.snap_enabled = this._snapEnabled;
this.config = config;
- this.snapLayersRefreshable = true;
// dispatch an event, it might be useful to know when the list of visible layer for snap changed
mainEventDispatcher.dispatch('snapping.layer.visibility.changed');
@@ -108,9 +113,19 @@ export default class Snapping {
this._snapLayers = visibleLayers.concat(snapLayers);
}
+ // Ensure snap layer is added to map when available
+ this._ensureMapReady = () => {
+ if (!this._mapReady && mainLizmap.map) {
+ mainLizmap.map.addToolLayer(this._snapLayer);
+ this._mapReady = true;
+ }
+ };
+
// Activate snap when a layer is edited
mainEventDispatcher.addListener(
() => {
+ this._ensureMapReady();
+
// Get snapping configuration for edited layer
for (const editionLayer in this._lizmap3.config.editionLayers) {
if (this._lizmap3.config.editionLayers.hasOwnProperty(editionLayer)) {
@@ -150,21 +165,8 @@ export default class Snapping {
}
if (this._config !== undefined){
- // Configure snapping
- const snapControl = this._lizmap3.controls.snapControl;
-
- // Set edition layer as main layer
- snapControl.setLayer(this._edition.editLayer);
-
- snapControl.targets[0].node = this._config.snap_vertices;
- snapControl.targets[0].vertex = this._config.snap_intersections;
- snapControl.targets[0].edge = this._config.snap_segments;
- snapControl.targets[0].nodeTolerance = this._config.snap_vertices_tolerance;
- snapControl.targets[0].vertexTolerance = this._config.snap_intersections_tolerance;
- snapControl.targets[0].edgeTolerance = this._config.snap_segments_tolerance;
-
// Listen to moveend event and to layers visibility changes to able data refreshing
- this._lizmap3.map.events.register('moveend', this, this._setSnapLayersRefreshable);
+ mainLizmap.map.on('moveend', this._refreshSnapDataOnMoveEnd);
this._rootMapGroup.addListener(
this._setSnapLayersVisibility,
['layer.visibility.changed','group.visibility.changed']
@@ -191,11 +193,13 @@ export default class Snapping {
this._pendingMapReadyListener = null;
}
this.active = false;
- this._snapLayer.destroyFeatures();
+ this._snapSource.clear();
this.config = undefined;
- // Remove listener to moveend event to layers visibility event
- this._lizmap3.map.events.unregister('moveend', this, this._setSnapLayersRefreshable);
+ // Remove listener to moveend event and layers visibility event
+ if (mainLizmap.map) {
+ mainLizmap.map.un('moveend', this._refreshSnapDataOnMoveEnd);
+ }
this._rootMapGroup.removeListener(
this._setSnapLayersVisibility,
['layer.visibility.changed','group.visibility.changed']
@@ -244,97 +248,43 @@ export default class Snapping {
}
}
- /**
- * Log a WFS snap failure and surface a user-visible message, once per refresh batch.
- * Called from both the rejection and the "no valid FeatureCollection" path.
- * @param {string} layerName - the layer whose WFS request failed
- * @param {Error|object|string} detail - the error or payload that triggered the notice
- * @private
- */
- _notifySnapWfsError(layerName, detail) {
- console.warn('Snapping: WFS request failed for layer', layerName, detail);
- if (this._wfsErrorNotified) return;
- this._wfsErrorNotified = true;
- const msg = lizDict['snapping.message.wfs_error']
- || 'Snapping: failed to load data for some layers — snap may be incomplete.';
- this._lizmap3.addMessage(msg, 'error', true, 7000);
- }
-
getSnappingData () {
- // Empty snapping layer first
- this._snapLayer.destroyFeatures();
-
- // Reset the once-per-refresh error notification flag so a new batch of
- // requests can re-surface a user-visible message if WFS still fails.
- this._wfsErrorNotified = false;
+ // Empty snapping source first
+ this._snapSource.clear();
// filter only visible layers and toggled layers on the the snap list
const currentSnapLayers = this._snapLayers.filter(
(layerId) => this._snapEnabled[layerId] && this._snapToggled[layerId]
);
- // Request the map projection so QGIS Server reprojects server-side with full
- // PROJ accuracy (including datum grid shifts). This prevents the ~cm coordinate
- // drift that occurs when OL2 performs a client-side EPSG:4326 → map-projection
- // transform using a simplified Helmert approximation instead of an NTv2 grid.
- const mapProjection = this._lizmap3.map.getProjection();
- const mapExtent = this._restrictToMapExtent ? this._lizmap3.map.getExtent() : null;
- const wfs = new WFS();
- const gFormat = new OpenLayers.Format.GeoJSON({ ignoreExtraDims: true });
+ const mapProjection = mainLizmap.map.getView().getProjection().getCode();
+ // TODO : group async calls with Promises
for (const snapLayer of currentSnapLayers) {
- const layerConfigById = this._lizmap3.getLayerConfigById(snapLayer);
- if (!layerConfigById || !layerConfigById[0]) continue;
-
- const layerName = layerConfigById[0];
- const layerConf = this._lizmap3.config.layers[layerName];
- if (!layerConf) continue;
-
- // Resolve typename (same logic as getVectorLayerWfsUrl)
- let typeName = layerName.split(' ').join('_');
- if (layerConf.hasOwnProperty('shortname') && layerConf['shortname']) typeName = layerConf['shortname'];
- else if (layerConf.hasOwnProperty('typename') && layerConf['typename']) typeName = layerConf['typename'];
-
- const wfsOptions = {
- VERSION: '1.1.0',
- TYPENAME: typeName,
- SRSNAME: mapProjection,
- MAXFEATURES: this._maxFeatures,
- };
- // Apply existing layer filter if present (e.g. login-based filter)
- if (layerConf.hasOwnProperty('request_params') && layerConf['request_params'].hasOwnProperty('filter')) {
- const layerFilter = layerConf['request_params']['filter'];
- if (layerFilter) {
- wfsOptions['EXP_FILTER'] = layerFilter.replace(layerName + ':', '');
- }
- }
+ lizMap.getFeatureData(this._lizmap3.getLayerConfigById(snapLayer)[0], null, null, 'geom', this._restrictToMapExtent, null, this._maxFeatures,
+ (fName, fFilter, fFeatures) => {
- // Append CRS code so the server interprets the extent in the map projection
- if (mapExtent) {
- wfsOptions['BBOX'] = [mapExtent.left, mapExtent.bottom, mapExtent.right, mapExtent.top].join(',') + ',' + mapProjection;
- }
+ // Transform features
+ const snapLayerConfig = lizMap.config.layers[fName];
+ let snapLayerCrs = snapLayerConfig['featureCrs'];
+ if (!snapLayerCrs) {
+ snapLayerCrs = snapLayerConfig['crs'];
+ }
- wfs.getFeature(wfsOptions).then(data => {
- if (!data || !Array.isArray(data.features)) {
- // The WFS endpoint returned something (no rejection) but not a
- // FeatureCollection — most likely an OGC ExceptionReport wrapped as
- // JSON. Treat as a failure so the user sees that snap may be incomplete.
- this._notifySnapWfsError(layerName, data);
- return;
- }
- // Features are already in map projection — no client-side reprojection needed.
- const tfeatures = gFormat.read({
- type: 'FeatureCollection',
- features: data.features
+ const gFormat = new GeoJSON();
+ const tfeatures = gFormat.readFeatures(
+ { type: 'FeatureCollection', features: fFeatures },
+ {
+ dataProjection: snapLayerCrs,
+ featureProjection: mapProjection
+ }
+ );
+
+ // Add features
+ this._snapSource.addFeatures(tfeatures);
});
- this._snapLayer.addFeatures(tfeatures);
- }).catch(err => {
- this._notifySnapWfsError(layerName, err);
- });
}
-
- this.snapLayersRefreshable = false;
}
toggle(){
@@ -382,16 +332,6 @@ export default class Snapping {
config.snap_on_layers = this._snapToggled;
this.config = config;
- this.snapLayersRefreshable = true;
- }
-
- get snapLayersRefreshable(){
- return this._snapLayersRefreshable;
- }
-
- set snapLayersRefreshable(refreshable) {
- this._snapLayersRefreshable = refreshable;
- mainEventDispatcher.dispatch('snapping.refreshable');
}
get active() {
@@ -401,22 +341,68 @@ export default class Snapping {
set active(active) {
this._active = active;
- // (de)activate snap control
+ // (de)activate snap interaction
if (this._active) {
this.getSnappingData();
- this._lizmap3.controls.snapControl.activate();
+ this._createSnapInteraction();
} else {
- // Disable refresh button when snapping is inactive
- this.snapLayersRefreshable = false;
- this._lizmap3.controls.snapControl.deactivate();
+ this._removeSnapInteraction();
}
- // Set snap layer visibility
- this._snapLayer.setVisibility(this._active);
+ // Show snap layer when active so users can see snappable features
+ this._snapLayer.setVisible(this._active);
mainEventDispatcher.dispatch('snapping.active');
}
+ /**
+ * Create and add the OL6 Snap interaction to the map
+ * @private
+ */
+ _createSnapInteraction() {
+ this._removeSnapInteraction();
+
+ if (!this._config || !mainLizmap.map) return;
+
+ this._snapInteraction = new Snap({
+ source: this._snapSource,
+ vertex: this._config.snap_vertices || this._config.snap_intersections,
+ edge: this._config.snap_segments,
+ pixelTolerance: Math.max(
+ parseInt(this._config.snap_vertices_tolerance) || 10,
+ parseInt(this._config.snap_segments_tolerance) || 10
+ )
+ });
+
+ mainLizmap.map.addInteraction(this._snapInteraction);
+ }
+
+ /**
+ * Remove the OL6 Snap interaction from the map
+ * @private
+ */
+ _removeSnapInteraction() {
+ if (this._snapInteraction && mainLizmap.map) {
+ mainLizmap.map.removeInteraction(this._snapInteraction);
+ this._snapInteraction = null;
+ }
+ }
+
+ /**
+ * Re-add the Snap interaction so it sits at the top of the map's
+ * interactions list, which means OL processes it *before* whatever
+ * Draw / Modify / Translate was just added by another module.
+ *
+ * Callers (e.g. the Digitizing module) invoke this after adding a new
+ * drawing interaction so snapping continues to work against the latest
+ * interaction in the stack. No-op when snapping is inactive.
+ */
+ reorderSnapInteraction() {
+ if (this._active && mainLizmap.map && this._config) {
+ this._createSnapInteraction();
+ }
+ }
+
get config() {
return this._config;
}
@@ -424,6 +410,11 @@ export default class Snapping {
set config(config) {
this._config = config;
+ // Re-create snap interaction with updated config when active
+ if (this._active && this._config) {
+ this._createSnapInteraction();
+ }
+
mainEventDispatcher.dispatch('snapping.config');
}
}
diff --git a/tests/end2end/playwright/snap.spec.js b/tests/end2end/playwright/snap.spec.js
index e98ce3e6ac..72995e7c7d 100644
--- a/tests/end2end/playwright/snap.spec.js
+++ b/tests/end2end/playwright/snap.spec.js
@@ -1,7 +1,5 @@
// @ts-check
import { test, expect } from '@playwright/test';
-import { expect as requestExpect } from './fixtures/expect-request.js'
-import { expect as responseExpect } from './fixtures/expect-response.js'
import { ProjectPage } from "./pages/project";
test.describe('Snap on edition', () => {
@@ -10,161 +8,14 @@ test.describe('Snap on edition', () => {
await project.open();
});
- test('Snap WFS GetFeature uses WFS 1.1.0 with SRSNAME in the map projection', async ({ page }) => {
- const project = new ProjectPage(page, 'form_edition_multilayer_snap');
-
- // Intercept the snap GetFeature request before opening the form —
- // snapping is auto-activated on form display for this project.
- const snapWfsRequestPromise = project.waitForGetFeatureRequest('form_edition_snap_point');
-
- // Track whether a DescribeFeatureType is sent alongside the snap request.
- // With the new WFS 1.1.0 path we no longer go through getFeatureData(), so
- // no DescribeFeatureType should be triggered.
- let describeFeatureTypeSent = false;
- page.on('request', request => {
- if (
- request.method() === 'POST'
- && request.postData()?.includes('DescribeFeatureType') === true
- && request.postData()?.includes('form_edition_snap_point') === true
- ) {
- describeFeatureTypeSent = true;
- }
- });
-
- const formRequest = await project.openEditingFormWithLayer('form_edition_snap_control');
- await formRequest.response();
- await page.getByRole('tab', { name: 'Digitization' }).click();
-
- const snapWfsRequest = await snapWfsRequestPromise;
-
- // The WFS request must use version 1.1.0 with an explicit SRSNAME so that
- // QGIS Server reprojects features server-side instead of the client using
- // proj4js (which lacks datum-grid shifts and introduces ~cm coordinate drift).
- requestExpect(snapWfsRequest).toContainParametersInPostData({
- SERVICE: 'WFS',
- VERSION: '1.1.0',
- REQUEST: 'GetFeature',
- TYPENAME: 'form_edition_snap_point',
- SRSNAME: 'EPSG:4326', // the project's map projection
- });
-
- // Confirm the snap response is valid GeoJSON, then verify no DescribeFeatureType was sent.
- responseExpect(await snapWfsRequest.response()).toBeGeoJson();
- expect(describeFeatureTypeSent).toBeFalsy();
- });
-
- test('Snap WFS GetFeature uses map projection SRSNAME for cross-CRS layer', async ({ page }, testInfo) => {
- // Project is in EPSG:3857; snap target is stored in EPSG:2154 (Lambert-93).
- // The WFS request must ask for features in the MAP projection (SRSNAME=EPSG:3857)
- // and include a 5-element BBOX so the server can apply the spatial filter correctly.
- // Snapping is auto-activated on form display (snap_on_start: True).
- const project = new ProjectPage(page, 'form_edition_snap_datum_shift');
- project.waitForGetLegendGraphicDuringLoad = false;
-
- await project.open();
-
- const snapWfsRequestPromise = project.waitForGetFeatureRequest('snap_datum_shift_target');
-
- const formRequest = await project.openEditingFormWithLayer('snap_datum_shift_edit');
- responseExpect(await formRequest.response()).toBeTextPlain();
-
- await page.getByRole('tab', { name: 'Digitization' }).click();
-
- const snapWfsRequest = await snapWfsRequestPromise;
- const rawPostData = snapWfsRequest.postData() ?? '';
- const postData = new URLSearchParams(rawPostData);
-
- // Attach the full POST body to the test report for easy inspection on failure.
- await testInfo.attach('snap-wfs-request-post-data', {
- body: rawPostData,
- contentType: 'application/x-www-form-urlencoded',
- });
-
- requestExpect(snapWfsRequest).toContainParametersInPostData({
- SERVICE: 'WFS',
- VERSION: '1.1.0',
- REQUEST: 'GetFeature',
- TYPENAME: 'snap_datum_shift_target',
- SRSNAME: 'EPSG:3857',
- });
-
- // BBOX must be the 5-element WFS 1.1.0 format ending with the CRS code.
- const bbox = postData.get('BBOX') ?? '';
- expect(bbox, `BBOX must be 5-element WFS 1.1.0 format (x,y,x,y,EPSG:3857), got: "${bbox}"`
- ).toMatch(/^-?[\d.]+,-?[\d.]+,-?[\d.]+,-?[\d.]+,EPSG:3857$/);
-
- responseExpect(await snapWfsRequest.response()).toBeGeoJson();
- });
-
- test('Snap features from EPSG:2154 layer arrive in EPSG:3857 coordinates', async ({ page }, testInfo) => {
- // The PostGIS WFS path must transform geometries into the requested output CRS
- // (SRSNAME=EPSG:3857). Without the fix, coordinates would come back in EPSG:4326
- // (~3.86–3.92 / 43.61–43.64) or the layer native CRS EPSG:2154 (~769000–774000 /
- // 6280000–6283000), both obviously outside the valid EPSG:3857 range for this area
- // (~430000–435000 / 5406000–5408000).
- // Snapping is auto-activated on form display (snap_on_start: True).
- const project = new ProjectPage(page, 'form_edition_snap_datum_shift');
- project.waitForGetLegendGraphicDuringLoad = false;
-
- await project.open();
-
- const snapWfsRequestPromise = project.waitForGetFeatureRequest('snap_datum_shift_target');
-
- const formRequest = await project.openEditingFormWithLayer('snap_datum_shift_edit');
- await formRequest.response();
-
- await page.getByRole('tab', { name: 'Digitization' }).click();
-
- const snapWfsRequest = await snapWfsRequestPromise;
- const snapWfsResponse = await snapWfsRequest.response();
-
- // Confirm the server returned valid GeoJSON before inspecting coordinates.
- responseExpect(snapWfsResponse).toBeGeoJson();
-
- const geojson = await snapWfsResponse?.json();
-
- // Attach the full server response to the test report.
- await testInfo.attach('snap-wfs-response-body', {
- body: JSON.stringify(geojson),
- contentType: 'application/json',
- });
-
- console.log('[snap datum-shift] WFS response status:', snapWfsResponse?.status());
- console.log('[snap datum-shift] Feature count:', geojson.features?.length ?? 0);
-
- expect(geojson.features, 'Response must contain a features array').toBeDefined();
- expect(geojson.features.length, 'At least one snap target feature must be returned').toBeGreaterThan(0);
-
- for (const feature of geojson.features) {
- const [x, y] = feature.geometry.coordinates;
-
- console.log(`[snap datum-shift] Feature id=${feature.id} coords: x=${x.toFixed(2)}, y=${y.toFixed(2)}`);
-
- // Diagnose likely failure modes in the message for faster debugging:
- // 4326 → x ≈ 3.86, y ≈ 43.6
- // 2154 → x ≈ 769 000, y ≈ 6 280 000
- // 3857 → x ≈ 431 000, y ≈ 5 407 000 ✓
- const hint = x < 10
- ? `looks like EPSG:4326 (lon/lat) — server did not transform to 3857`
- : x > 500000
- ? `looks like EPSG:2154 (Lambert-93) — server returned native CRS instead of 3857`
- : '';
- expect(x, `x=${x.toFixed(2)} out of EPSG:3857 range for this area [420000–445000]${hint ? ' — ' + hint : ''}`
- ).toBeGreaterThan(420000);
- expect(x, `x=${x.toFixed(2)} out of EPSG:3857 range for this area [420000–445000]${hint ? ' — ' + hint : ''}`
- ).toBeLessThan(445000);
- expect(y, `y=${y.toFixed(2)} out of EPSG:3857 range for this area [5390000–5420000]`
- ).toBeGreaterThan(5390000);
- expect(y, `y=${y.toFixed(2)} out of EPSG:3857 range for this area [5390000–5420000]`
- ).toBeLessThan(5420000);
- }
- });
-
test('Snap panel functionalities', async ({ page }) => {
const project = new ProjectPage(page, 'form_edition_multilayer_snap');
- // Set up request watcher before opening the form, as snapping is auto-activated on form display
- let getSnappingPointFeatureRequestPromise = project.waitForGetFeatureRequest('form_edition_snap_point');
+ // Set up request watchers before opening the form, as snapping is auto-activated on form display
+ let getSnappingPointFeatureRequestPromise = page.waitForRequest(
+ request => request.method() === 'POST' && request.postData() != null && request.postData()?.includes('GetFeature') === true && request.postData()?.includes('form_edition_snap_point') === true);
+ let getSnappingPointDescribeFeatureRequestPromise = page.waitForRequest(
+ request => request.method() === 'POST' && request.postData() != null && request.postData()?.includes('DescribeFeatureType') === true && request.postData()?.includes('form_edition_snap_point') === true);
const formRequest = await project.openEditingFormWithLayer('form_edition_snap_control');
await formRequest.response();
@@ -177,10 +28,7 @@ test.describe('Snap on edition', () => {
await page.getByRole('tab', { name: 'Digitization' }).click()
// snapping is auto-activated when snap layers are configured
- responseExpect(await (await getSnappingPointFeatureRequestPromise).response()).toBeGeoJson();
-
- // check snap panel and controls
- await expect(page.locator("#edition-point-coord-form-group").getByRole("button").nth(2)).toBeDisabled();
+ await Promise.all([getSnappingPointFeatureRequestPromise, getSnappingPointDescribeFeatureRequestPromise])
//check layer list in the panel
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer")).toHaveCount(3);
@@ -210,9 +58,6 @@ test.describe('Snap on edition', () => {
// back to digitization panel
await page.locator('#button-edition').click();
- // refresh button now should be enabled
- await expect(page.locator("#edition-point-coord-form-group").getByRole("button").nth(2)).toBeEnabled();
-
// check current snap panel
// now the order of the elements on the list should be changed in Line snap, Point snap (both enabled with Line snap unchecked), Polygon snap
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer")).toHaveCount(3);
@@ -235,30 +80,20 @@ test.describe('Snap on edition', () => {
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer").nth(2).locator("label")).toHaveText("Polygon snap");
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer").nth(2).locator("label")).toContainClass("snap-disabled");
- // activate snap on line and refresh snap
+ // activate snap on line layer
await page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer").nth(0).locator("input").check()
- let getSnappingLineFeatureRequestPromise = project.waitForGetFeatureRequest('form_edition_snap_line');
-
- await page.locator("#edition-point-coord-form-group").getByRole("button").nth(2).click()
-
- responseExpect(await (await getSnappingLineFeatureRequestPromise).response()).toBeGeoJson();
-
- await expect(page.locator("#edition-point-coord-form-group").getByRole("button").nth(2)).toBeDisabled();
+ await page.waitForTimeout(300);
// do the same for the polygon layer
-
- // turn on the line layer
+ // turn on the polygon layer
await page.locator('#button-switcher').click();
await page.getByTestId('form_edition_snap_polygon').getByLabel('Polygon snap').click();
// back to digitization panel
await page.locator('#button-edition').click();
- // refresh button now should be enabled
- await expect(page.locator("#edition-point-coord-form-group").getByRole("button").nth(2)).toBeEnabled();
-
// check current snap panel
// now the order of the elements on the list should be Line snap, Point snap, Polygon snap. All check boxes enabled, polygon unchecked
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer")).toHaveCount(3);
@@ -281,18 +116,12 @@ test.describe('Snap on edition', () => {
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer").nth(2).locator("label")).toHaveText("Polygon snap");
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer").nth(2).locator("label")).not.toContainClass("snap-disabled");
- // activate snap on polygon and refresh snap
+ // activate snap on polygon layer
await page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer").nth(2).locator("input").check()
- let getSnappingPolygonFeatureRequestPromise = project.waitForGetFeatureRequest('form_edition_snap_polygon');
+ await page.waitForTimeout(300);
- await page.locator("#edition-point-coord-form-group").getByRole("button").nth(2).click()
-
- responseExpect(await (await getSnappingPolygonFeatureRequestPromise).response()).toBeGeoJson();
-
- await expect(page.locator("#edition-point-coord-form-group").getByRole("button").nth(2)).toBeDisabled();
-
- // disable all layer
+ // disable all layers
await project.switcher.click();
await page.getByTestId('form_edition_snap_point').getByLabel('Point snap').click();
await page.getByTestId('form_edition_snap_line').getByLabel('Line snap').click();
@@ -301,9 +130,6 @@ test.describe('Snap on edition', () => {
// back to digitization panel
await page.locator('#button-edition').click();
- // refresh button enabled
- await expect(page.locator("#edition-point-coord-form-group").getByRole("button").nth(2)).toBeEnabled();
-
// all layers disabled and checked. Layer order Line, Point, Polygon
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer")).toHaveCount(3);
@@ -334,9 +160,6 @@ test.describe('Snap on edition', () => {
// back to digitization panel
await page.locator('#button-edition').click();
- // refresh button enabled
- await expect(page.locator("#edition-point-coord-form-group").getByRole("button").nth(2)).toBeEnabled();
-
await expect(page.locator("#edition-point-coord-form-group .snap-layers-list .snap-layer")).toHaveCount(3);
// line first