@@ -56,6 +56,112 @@ test.describe('Snap on edition', () => {
5656 expect ( describeFeatureTypeSent ) . toBeFalsy ( ) ;
5757 } ) ;
5858
59+ test ( 'Snap WFS GetFeature uses map projection SRSNAME for cross-CRS layer' , async ( { page } , testInfo ) => {
60+ // Project is in EPSG:3857; snap target is stored in EPSG:2154 (Lambert-93).
61+ // The WFS request must ask for features in the MAP projection (SRSNAME=EPSG:3857)
62+ // and include a 5-element BBOX so the server can apply the spatial filter correctly.
63+ const project = new ProjectPage ( page , 'form_edition_snap_datum_shift' ) ;
64+ await project . open ( ) ;
65+
66+ const snapWfsRequestPromise = page . waitForRequest (
67+ request => request . method ( ) === 'POST'
68+ && request . postData ( ) ?. includes ( 'GetFeature' ) === true
69+ && request . postData ( ) ?. includes ( 'snap_datum_shift_target' ) === true
70+ ) ;
71+
72+ await project . openEditingFormWithLayer ( 'snap_datum_shift_edit' ) ;
73+ await page . getByRole ( 'tab' , { name : 'Digitization' } ) . click ( ) ;
74+
75+ const snapWfsRequest = await snapWfsRequestPromise ;
76+ const rawPostData = snapWfsRequest . postData ( ) ?? '' ;
77+ const postData = new URLSearchParams ( rawPostData ) ;
78+
79+ // Attach the full POST body to the test report for easy inspection on failure.
80+ await testInfo . attach ( 'snap-wfs-request-post-data' , {
81+ body : rawPostData ,
82+ contentType : 'application/x-www-form-urlencoded' ,
83+ } ) ;
84+
85+ console . log ( '[snap datum-shift] WFS request parameters:' ) ;
86+ for ( const [ key , value ] of postData . entries ( ) ) {
87+ console . log ( ` ${ key } = ${ value } ` ) ;
88+ }
89+
90+ requestExpect ( snapWfsRequest ) . toContainParametersInPostData ( {
91+ SERVICE : 'WFS' ,
92+ VERSION : '1.1.0' ,
93+ REQUEST : 'GetFeature' ,
94+ TYPENAME : 'snap_datum_shift_target' ,
95+ SRSNAME : 'EPSG:3857' ,
96+ } ) ;
97+
98+ // BBOX must be the 5-element WFS 1.1.0 format ending with the CRS code.
99+ const bbox = postData . get ( 'BBOX' ) ?? '' ;
100+ console . log ( '[snap datum-shift] BBOX value:' , bbox ) ;
101+ expect ( bbox , `BBOX must be 5-element WFS 1.1.0 format (x,y,x,y,EPSG:3857), got: "${ bbox } "`
102+ ) . toMatch ( / ^ - ? [ \d . ] + , - ? [ \d . ] + , - ? [ \d . ] + , - ? [ \d . ] + , E P S G : 3 8 5 7 $ / ) ;
103+ } ) ;
104+
105+ test ( 'Snap features from EPSG:2154 layer arrive in EPSG:3857 coordinates' , async ( { page } , testInfo ) => {
106+ // The PostGIS WFS path must transform geometries into the requested output CRS
107+ // (SRSNAME=EPSG:3857). Without the fix, coordinates would come back in EPSG:4326
108+ // (~3.86–3.92 / 43.61–43.64) or the layer native CRS EPSG:2154 (~769000–774000 /
109+ // 6280000–6283000), both obviously outside the valid EPSG:3857 range for this area
110+ // (~430000–435000 / 5406000–5408000).
111+ const project = new ProjectPage ( page , 'form_edition_snap_datum_shift' ) ;
112+ await project . open ( ) ;
113+
114+ const snapWfsResponsePromise = page . waitForResponse (
115+ response => response . request ( ) . method ( ) === 'POST'
116+ && response . request ( ) . postData ( ) ?. includes ( 'GetFeature' ) === true
117+ && response . request ( ) . postData ( ) ?. includes ( 'snap_datum_shift_target' ) === true
118+ ) ;
119+
120+ await project . openEditingFormWithLayer ( 'snap_datum_shift_edit' ) ;
121+ await page . getByRole ( 'tab' , { name : 'Digitization' } ) . click ( ) ;
122+
123+ const snapWfsResponse = await snapWfsResponsePromise ;
124+ const responseBody = await snapWfsResponse . text ( ) ;
125+
126+ // Attach the full server response to the test report.
127+ await testInfo . attach ( 'snap-wfs-response-body' , {
128+ body : responseBody ,
129+ contentType : 'application/json' ,
130+ } ) ;
131+
132+ const geojson = JSON . parse ( responseBody ) ;
133+
134+ console . log ( '[snap datum-shift] WFS response status:' , snapWfsResponse . status ( ) ) ;
135+ console . log ( '[snap datum-shift] Feature count:' , geojson . features ?. length ?? 0 ) ;
136+
137+ expect ( geojson . features , 'Response must contain a features array' ) . toBeDefined ( ) ;
138+ expect ( geojson . features . length , 'At least one snap target feature must be returned' ) . toBeGreaterThan ( 0 ) ;
139+
140+ for ( const feature of geojson . features ) {
141+ const [ x , y ] = feature . geometry . coordinates ;
142+
143+ console . log ( `[snap datum-shift] Feature id=${ feature . id } coords: x=${ x . toFixed ( 2 ) } , y=${ y . toFixed ( 2 ) } ` ) ;
144+
145+ // Diagnose likely failure modes in the message for faster debugging:
146+ // 4326 → x ≈ 3.86, y ≈ 43.6
147+ // 2154 → x ≈ 769 000, y ≈ 6 280 000
148+ // 3857 → x ≈ 431 000, y ≈ 5 407 000 ✓
149+ const hint = x < 10
150+ ? `looks like EPSG:4326 (lon/lat) — server did not transform to 3857`
151+ : x > 500000
152+ ? `looks like EPSG:2154 (Lambert-93) — server returned native CRS instead of 3857`
153+ : '' ;
154+ expect ( x , `x=${ x . toFixed ( 2 ) } out of EPSG:3857 range for this area [420000–445000]${ hint ? ' — ' + hint : '' } `
155+ ) . toBeGreaterThan ( 420000 ) ;
156+ expect ( x , `x=${ x . toFixed ( 2 ) } out of EPSG:3857 range for this area [420000–445000]${ hint ? ' — ' + hint : '' } `
157+ ) . toBeLessThan ( 445000 ) ;
158+ expect ( y , `y=${ y . toFixed ( 2 ) } out of EPSG:3857 range for this area [5390000–5420000]`
159+ ) . toBeGreaterThan ( 5390000 ) ;
160+ expect ( y , `y=${ y . toFixed ( 2 ) } out of EPSG:3857 range for this area [5390000–5420000]`
161+ ) . toBeLessThan ( 5420000 ) ;
162+ }
163+ } ) ;
164+
59165 test ( 'Snap panel functionalities' , async ( { page } ) => {
60166 const project = new ProjectPage ( page , 'form_edition_multilayer_snap' ) ;
61167
0 commit comments