diff --git a/src/services/OSM/OSM.test.jsx b/src/services/OSM/OSM.test.jsx
index 7c5811a8e..a7f1a89a0 100644
--- a/src/services/OSM/OSM.test.jsx
+++ b/src/services/OSM/OSM.test.jsx
@@ -60,7 +60,10 @@ describe("OSM Service Functions", () => {
Object.entries(statusToError).forEach(([status, error]) => {
test(`should handle ${status} error`, async () => {
- global.fetch.mockResolvedValueOnce({ ok: false, status: Number(status) });
+ global.fetch.mockResolvedValueOnce({
+ ok: false,
+ status: Number(status),
+ });
await expect(fetchOSMData("0,0,1,1")).rejects.toEqual(error);
});
});
@@ -72,7 +75,10 @@ describe("OSM Service Functions", () => {
const testXMLResponses = [
{ xml: ``, expectedLength: 1 },
- { xml: ``, expectedLength: 1 },
+ {
+ xml: ``,
+ expectedLength: 1,
+ },
{ xml: ``, expectedLength: 1 },
];
@@ -92,6 +98,22 @@ describe("OSM Service Functions", () => {
expect(elements.length).toBe(expectedLength);
});
});
+
+ describe("handleOSMError", () => {
+ const errorCases = [
+ { status: 400, error: AppErrors.osm.requestTooLarge },
+ { status: 404, error: AppErrors.osm.elementMissing },
+ { status: 509, error: AppErrors.osm.bandwidthExceeded },
+ { status: 418, error: AppErrors.osm.fetchFailure }, // Unknown status
+ ];
+
+ errorCases.forEach(({ status, error }) => {
+ test(`should handle ${status} error`, async () => {
+ global.fetch.mockResolvedValueOnce({ ok: false, status });
+ await expect(fetchOSMData("0,0,1,1")).rejects.toEqual(error);
+ });
+ });
+ });
});
describe("fetchOSMElement", () => {
@@ -103,7 +125,10 @@ describe("OSM Service Functions", () => {
Object.entries(statusToError).forEach(([status, error]) => {
test(`should handle ${status} error`, async () => {
- global.fetch.mockResolvedValueOnce({ ok: false, status: Number(status) });
+ global.fetch.mockResolvedValueOnce({
+ ok: false,
+ status: Number(status),
+ });
await expect(fetchOSMElement("node/12345")).rejects.toEqual(error);
});
});
@@ -177,18 +202,21 @@ describe("OSM Service Functions", () => {
{
history: {
elements: [
- { id: "1", changeset: "100" },
- { id: "2", changeset: "101" },
+ { id: "1", changeset: 100 },
+ { id: "2", changeset: 101 },
],
},
- changesetsXML: ``,
+ changesetsXML: `
+
+
+ `,
expectedLength: 2,
},
{
history: {
elements: [
- { id: "1", changeset: "999" },
- { id: "2", changeset: "888" },
+ { id: "1", changeset: 999 },
+ { id: "2", changeset: 888 },
],
},
changesetsXML: "",
@@ -199,31 +227,131 @@ describe("OSM Service Functions", () => {
testCases.forEach(({ history, changesetsXML, expectedLength }) => {
test("should handle changesets correctly", async () => {
global.fetch
- .mockResolvedValueOnce({ ok: true, json: vi.fn().mockResolvedValue(history) })
- .mockResolvedValueOnce({ ok: true, text: vi.fn().mockResolvedValue(changesetsXML) });
+ .mockResolvedValueOnce({
+ ok: true,
+ json: vi.fn().mockResolvedValue(history),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ text: vi.fn().mockResolvedValue(changesetsXML),
+ });
const result = await fetchOSMElementHistory("way/12345", true);
+
expect(result).toHaveLength(expectedLength);
- expect(result[0].changeset).toBe(history.elements[0].changeset);
- expect(result[1].changeset).toBe(history.elements[1].changeset);
+
+ result.forEach((element, index) => {
+ const originalChangeset = history.elements[index].changeset;
+
+ // If the changeset was found in the XML response, it should be an object
+ const changesetInXML = changesetsXML.includes(`id="${originalChangeset}"`);
+ if (changesetInXML) {
+ expect(element.changeset).toEqual(
+ expect.objectContaining({
+ id: originalChangeset,
+ details: expect.any(String),
+ }),
+ );
+ } else {
+ // If not found in XML, it should remain as a number
+ expect(element.changeset).toBe(originalChangeset);
+ }
+ });
});
});
- test("should handle 404 not found error", async () => {
- global.fetch.mockResolvedValueOnce({ ok: false, status: 404 });
- await expect(fetchOSMElementHistory("way/12345", true)).rejects.toEqual(
- AppErrors.osm.elementMissing,
+ test("should handle missing changesets gracefully", async () => {
+ const mockHistory = {
+ elements: [
+ { id: "1", changeset: 100 },
+ { id: "2", changeset: 101 },
+ ],
+ };
+
+ global.fetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: vi.fn().mockResolvedValue(mockHistory),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ text: vi.fn().mockResolvedValue(""),
+ });
+
+ const history = await fetchOSMElementHistory("way/12345", true);
+
+ expect(history).toHaveLength(2);
+ history.forEach((element, index) => {
+ // When no changeset data is found, the original number should be preserved
+ expect(element.changeset).toBe(mockHistory.elements[index].changeset);
+ });
+ });
+
+ test("should handle null changeset values", async () => {
+ const mockHistory = {
+ elements: [
+ { id: "1", changeset: null },
+ { id: "2", changeset: 101 },
+ ],
+ };
+
+ global.fetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: vi.fn().mockResolvedValue(mockHistory),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ text: vi
+ .fn()
+ .mockResolvedValue(
+ "",
+ ),
+ });
+
+ const history = await fetchOSMElementHistory("way/12345", true);
+
+ expect(history).toHaveLength(2);
+ expect(history[0].changeset).toBeNull();
+ expect(history[1].changeset).toEqual(
+ expect.objectContaining({
+ id: 101,
+ details: "some details",
+ }),
);
});
- test("should handle invalid element IDs gracefully", async () => {
+ test("should handle malformed changeset response", async () => {
const mockHistory = {
elements: [
- { id: "invalid_id", changeset: "100" },
- { id: "another_invalid_id", changeset: "101" },
+ { id: "1", changeset: 100 },
+ { id: "2", changeset: 101 },
],
};
+ // Mock a malformed XML response
+ global.fetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: vi.fn().mockResolvedValue(mockHistory),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ text: vi.fn().mockResolvedValue(""),
+ });
+
+ const history = await fetchOSMElementHistory("way/12345", true);
+ expect(history).toHaveLength(2);
+ // Changesets should remain as numbers when XML parsing fails
+ expect(history[0].changeset).toBe(100);
+ expect(history[1].changeset).toBe(101);
+ });
+
+ test("should handle empty changeset array", async () => {
+ const mockHistory = {
+ elements: [{ id: "1", changeset: 100 }],
+ };
+
global.fetch
.mockResolvedValueOnce({
ok: true,
@@ -231,14 +359,44 @@ describe("OSM Service Functions", () => {
})
.mockResolvedValueOnce({
ok: true,
+ // Return valid XML but with no changesets
text: vi.fn().mockResolvedValue(""),
});
const history = await fetchOSMElementHistory("way/12345", true);
+ expect(history).toHaveLength(1);
+ // Changeset should remain as number when no changeset data is found
+ expect(history[0].changeset).toBe(100);
+ });
- expect(history).toHaveLength(2);
- expect(history[0].changeset).toBe("100");
- expect(history[1].changeset).toBe("101");
+ test("should handle undefined elements in history response", async () => {
+ const mockHistory = {
+ elements: undefined,
+ };
+
+ global.fetch.mockResolvedValueOnce({
+ ok: true,
+ json: vi.fn().mockResolvedValue(mockHistory),
+ });
+
+ await expect(fetchOSMElementHistory("way/12345", true)).rejects.toEqual(
+ AppErrors.osm.fetchFailure,
+ );
+ });
+
+ test("should handle empty elements array in history response", async () => {
+ const mockHistory = {
+ elements: [],
+ };
+
+ global.fetch.mockResolvedValueOnce({
+ ok: true,
+ json: vi.fn().mockResolvedValue(mockHistory),
+ });
+
+ await expect(fetchOSMElementHistory("way/12345", true)).rejects.toEqual(
+ AppErrors.osm.fetchFailure,
+ );
});
});
@@ -252,7 +410,10 @@ describe("OSM Service Functions", () => {
Object.entries(statusToError).forEach(([status, error]) => {
test(`should handle ${status} error`, async () => {
- global.fetch.mockResolvedValueOnce({ ok: false, status: Number(status) });
+ global.fetch.mockResolvedValueOnce({
+ ok: false,
+ status: Number(status),
+ });
await expect(fetchOSMChangesets(["123"])).rejects.toEqual(error);
});
});
@@ -263,19 +424,26 @@ describe("OSM Service Functions", () => {
});
test("should handle valid changesets response", async () => {
- const changesetXML = '';
+ const changesetXML = `
+
+
+
+ `;
+
global.fetch.mockResolvedValueOnce({
ok: true,
text: vi.fn().mockResolvedValue(changesetXML),
});
- const result = await fetchOSMChangesets(["123"]);
- expect(result.length).toBe(1);
- expect(result[0].id.toString()).toBe("1");
- expect(result[0].details).toBe("details 1");
+ const result = await fetchOSMChangesets([1, 2]);
+ expect(result).toHaveLength(2);
+ expect(result[0]).toHaveProperty("id", 1);
+ expect(result[0]).toHaveProperty("details", "details 1");
+ expect(result[1]).toHaveProperty("id", 2);
+ expect(result[1]).toHaveProperty("details", "details 2");
});
- test("should handle empty changesets response", async () => {
+ test("should return empty array for empty changesets response", async () => {
global.fetch.mockResolvedValueOnce({
ok: true,
text: vi.fn().mockResolvedValue(""),