From 809a3e2a54704b1541268f3c8ed8220fb63c871a Mon Sep 17 00:00:00 2001 From: Roman Deev Date: Thu, 25 Dec 2025 03:26:53 +0300 Subject: [PATCH] check count members with role=outline --- src/building.js | 9 ++- test/building.test.js | 142 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/src/building.js b/src/building.js index 8221b67..fa0a80b 100644 --- a/src/building.js +++ b/src/building.js @@ -107,7 +107,14 @@ class Building { } else if (this.type === 'multipolygon') { this.outerElement = new MultiBuildingPart(id, this.fullXmlData, this.nodelist); } else { - const outlineRef = outerElementXml.querySelector('member[role="outline"]').getAttribute('ref'); + const outlines = outerElementXml.querySelectorAll('member[role="outline"]'); + if (outlines.length > 1) { + throw new Error(`Found multiple outline members in relation ${this.id}`); + } + if (outlines.length === 0) { + throw new Error(`The relation ${this.id} does not contain a member with the outline role`); + } + const outlineRef = outlines[0].getAttribute('ref'); const outline = this.fullXmlData.getElementById(outlineRef); const outlineType = outline.tagName.toLowerCase(); if (outlineType === 'way') { diff --git a/test/building.test.js b/test/building.test.js index 22be297..c14e08f 100644 --- a/test/building.test.js +++ b/test/building.test.js @@ -315,6 +315,148 @@ test('Test downloading type=building with multipolygon outline and multiple inne expect(global.fetch.mock.calls[2][0]).toBe(urlBase + 'map?bbox=30.4980057,59.9380365,30.4993839,59.9385087'); }); +const typeBuildingWithoutOutlineMember = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +test('Test outline member exist', async() => { + fetch.mockResponses( + [typeBuildingRelationFullResponse], // /relation/42/full + [outlineRelationFullResponse], // /relation/40/full + [typeBuildingWithoutOutlineMember], // /map call + ); + const innerData = await Building.downloadDataAroundBuilding('relation', '42'); + expect(() => new Building('42', innerData)) + .toThrow(new Error('The relation 42 does not contain a member with the outline role')); + const urlBase = 'https://api.openstreetmap.org/api/0.6/'; + expect(global.fetch.mock.calls[0][0]).toBe(urlBase + 'relation/42/full'); + expect(global.fetch.mock.calls[1][0]).toBe(urlBase + 'relation/40/full'); + expect(global.fetch.mock.calls[2][0]).toBe(urlBase + 'map?bbox=30.4980057,59.9380365,30.4993839,59.9385087'); +}); + +const typeBuildingWithMultipleOutlineMembers = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +test('Test that it is checked that there is only one member with outline role', async() => { + fetch.mockResponses( + [typeBuildingRelationFullResponse], // /relation/42/full + [outlineRelationFullResponse], // /relation/40/full + [typeBuildingWithMultipleOutlineMembers], // /map call + ); + const innerData = await Building.downloadDataAroundBuilding('relation', '42'); + expect(() => new Building('42', innerData)) + .toThrow(new Error('Found multiple outline members in relation 42')); + const urlBase = 'https://api.openstreetmap.org/api/0.6/'; + expect(global.fetch.mock.calls[0][0]).toBe(urlBase + 'relation/42/full'); + expect(global.fetch.mock.calls[1][0]).toBe(urlBase + 'relation/40/full'); + expect(global.fetch.mock.calls[2][0]).toBe(urlBase + 'map?bbox=30.4980057,59.9380365,30.4993839,59.9385087'); +}); + + test('Part must be within outline', () => { const data = `