mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-03-27 01:27:23 +01:00
Merge branch 'master' of https://github.com/Azgaar/Fantasy-Map-Generator
This commit is contained in:
commit
669896757d
49 changed files with 7696 additions and 5770 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
221
tests/e2e/load-map.spec.ts
Normal file
221
tests/e2e/load-map.spec.ts
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import path from "path";
|
||||
|
||||
test.describe("Map loading", () => {
|
||||
test.beforeEach(async ({ context, page }) => {
|
||||
await context.clearCookies();
|
||||
|
||||
await page.goto("/");
|
||||
await page.evaluate(() => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
});
|
||||
|
||||
// Wait for the hidden file input to be available
|
||||
await page.waitForSelector("#mapToLoad", { state: "attached" });
|
||||
});
|
||||
|
||||
test("should load a saved map file", async ({ page }) => {
|
||||
// Track errors during map loading
|
||||
const errors: string[] = [];
|
||||
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||
page.on("console", (msg) => {
|
||||
if (msg.type() === "error") {
|
||||
errors.push(`console.error: ${msg.text()}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Get the file input element and upload the map file
|
||||
const fileInput = page.locator("#mapToLoad");
|
||||
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||
await fileInput.setInputFiles(mapFilePath);
|
||||
|
||||
// Wait for map to be fully loaded
|
||||
// mapId is set at the very end of map loading in showStatistics()
|
||||
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||
timeout: 120000,
|
||||
});
|
||||
|
||||
// Additional wait for rendering to settle
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Verify map data is loaded
|
||||
const mapData = await page.evaluate(() => {
|
||||
const pack = (window as any).pack;
|
||||
return {
|
||||
hasStates: pack.states && pack.states.length > 1,
|
||||
hasBurgs: pack.burgs && pack.burgs.length > 1,
|
||||
hasCells: pack.cells && pack.cells.i && pack.cells.i.length > 0,
|
||||
hasRivers: pack.rivers && pack.rivers.length > 0,
|
||||
mapId: (window as any).mapId,
|
||||
};
|
||||
});
|
||||
|
||||
expect(mapData.hasStates).toBe(true);
|
||||
expect(mapData.hasBurgs).toBe(true);
|
||||
expect(mapData.hasCells).toBe(true);
|
||||
expect(mapData.hasRivers).toBe(true);
|
||||
expect(mapData.mapId).toBeDefined();
|
||||
|
||||
// Ensure no JavaScript errors occurred during loading
|
||||
// Filter out expected errors (external resources like Google Analytics, fonts)
|
||||
const criticalErrors = errors.filter(
|
||||
(e) =>
|
||||
!e.includes("fonts.googleapis.com") &&
|
||||
!e.includes("google-analytics") &&
|
||||
!e.includes("googletagmanager") &&
|
||||
!e.includes("Failed to load resource")
|
||||
);
|
||||
expect(criticalErrors).toEqual([]);
|
||||
});
|
||||
|
||||
test("loaded map should have correct SVG structure", async ({ page }) => {
|
||||
const errors: string[] = [];
|
||||
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||
page.on("console", (msg) => {
|
||||
if (msg.type() === "error") {
|
||||
errors.push(`console.error: ${msg.text()}`);
|
||||
}
|
||||
});
|
||||
|
||||
const fileInput = page.locator("#mapToLoad");
|
||||
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||
await fileInput.setInputFiles(mapFilePath);
|
||||
|
||||
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||
timeout: 120000,
|
||||
});
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Check essential SVG layers exist
|
||||
const layers = await page.evaluate(() => {
|
||||
return {
|
||||
ocean: !!document.getElementById("ocean"),
|
||||
lakes: !!document.getElementById("lakes"),
|
||||
coastline: !!document.getElementById("coastline"),
|
||||
rivers: !!document.getElementById("rivers"),
|
||||
borders: !!document.getElementById("borders"),
|
||||
burgs: !!document.getElementById("burgIcons"),
|
||||
labels: !!document.getElementById("labels"),
|
||||
};
|
||||
});
|
||||
|
||||
expect(layers.ocean).toBe(true);
|
||||
expect(layers.lakes).toBe(true);
|
||||
expect(layers.coastline).toBe(true);
|
||||
expect(layers.rivers).toBe(true);
|
||||
expect(layers.borders).toBe(true);
|
||||
expect(layers.burgs).toBe(true);
|
||||
expect(layers.labels).toBe(true);
|
||||
|
||||
const criticalErrors = errors.filter(
|
||||
(e) =>
|
||||
!e.includes("fonts.googleapis.com") &&
|
||||
!e.includes("google-analytics") &&
|
||||
!e.includes("googletagmanager") &&
|
||||
!e.includes("Failed to load resource")
|
||||
);
|
||||
expect(criticalErrors).toEqual([]);
|
||||
});
|
||||
|
||||
test("loaded map should preserve state data", async ({ page }) => {
|
||||
const errors: string[] = [];
|
||||
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||
page.on("console", (msg) => {
|
||||
if (msg.type() === "error") {
|
||||
errors.push(`console.error: ${msg.text()}`);
|
||||
}
|
||||
});
|
||||
|
||||
const fileInput = page.locator("#mapToLoad");
|
||||
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||
await fileInput.setInputFiles(mapFilePath);
|
||||
|
||||
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||
timeout: 120000,
|
||||
});
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Verify states have proper structure
|
||||
const statesData = await page.evaluate(() => {
|
||||
const pack = (window as any).pack;
|
||||
const states = pack.states.filter((s: any) => s.i !== 0); // exclude neutral
|
||||
|
||||
return {
|
||||
count: states.length,
|
||||
allHaveNames: states.every((s: any) => s.name && s.name.length > 0),
|
||||
allHaveCells: states.every((s: any) => s.cells > 0),
|
||||
allHaveArea: states.every((s: any) => s.area > 0),
|
||||
};
|
||||
});
|
||||
|
||||
expect(statesData.count).toBeGreaterThan(0);
|
||||
expect(statesData.allHaveNames).toBe(true);
|
||||
expect(statesData.allHaveCells).toBe(true);
|
||||
expect(statesData.allHaveArea).toBe(true);
|
||||
|
||||
const criticalErrors = errors.filter(
|
||||
(e) =>
|
||||
!e.includes("fonts.googleapis.com") &&
|
||||
!e.includes("google-analytics") &&
|
||||
!e.includes("googletagmanager") &&
|
||||
!e.includes("Failed to load resource")
|
||||
);
|
||||
expect(criticalErrors).toEqual([]);
|
||||
});
|
||||
|
||||
test("loaded map should preserve burg data", async ({ page }) => {
|
||||
const errors: string[] = [];
|
||||
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||
page.on("console", (msg) => {
|
||||
if (msg.type() === "error") {
|
||||
errors.push(`console.error: ${msg.text()}`);
|
||||
}
|
||||
});
|
||||
|
||||
const fileInput = page.locator("#mapToLoad");
|
||||
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||
await fileInput.setInputFiles(mapFilePath);
|
||||
|
||||
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||
timeout: 120000,
|
||||
});
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Verify burgs have proper structure
|
||||
const burgsData = await page.evaluate(() => {
|
||||
const pack = (window as any).pack;
|
||||
// Filter out placeholder (i=0) and removed burgs (removed=true or no name)
|
||||
const activeBurgs = pack.burgs.filter(
|
||||
(b: any) => b.i !== 0 && !b.removed && b.name
|
||||
);
|
||||
|
||||
return {
|
||||
count: activeBurgs.length,
|
||||
allHaveNames: activeBurgs.every(
|
||||
(b: any) => b.name && b.name.length > 0
|
||||
),
|
||||
allHaveCoords: activeBurgs.every(
|
||||
(b: any) => typeof b.x === "number" && typeof b.y === "number"
|
||||
),
|
||||
allHaveCells: activeBurgs.every(
|
||||
(b: any) => typeof b.cell === "number"
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
expect(burgsData.count).toBeGreaterThan(0);
|
||||
expect(burgsData.allHaveNames).toBe(true);
|
||||
expect(burgsData.allHaveCoords).toBe(true);
|
||||
expect(burgsData.allHaveCells).toBe(true);
|
||||
|
||||
const criticalErrors = errors.filter(
|
||||
(e) =>
|
||||
!e.includes("fonts.googleapis.com") &&
|
||||
!e.includes("google-analytics") &&
|
||||
!e.includes("googletagmanager") &&
|
||||
!e.includes("Failed to load resource")
|
||||
);
|
||||
expect(criticalErrors).toEqual([]);
|
||||
});
|
||||
});
|
||||
349
tests/e2e/zones-export.spec.ts
Normal file
349
tests/e2e/zones-export.spec.ts
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Zone Export", () => {
|
||||
test.beforeEach(async ({ context, page }) => {
|
||||
await context.clearCookies();
|
||||
|
||||
await page.goto("/");
|
||||
await page.evaluate(() => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
});
|
||||
|
||||
// Navigate with seed parameter and wait for full load
|
||||
await page.goto("/?seed=test-zones-export&width=1280&height=720");
|
||||
|
||||
// Wait for map generation to complete
|
||||
await page.waitForFunction(
|
||||
() => (window as any).mapId !== undefined,
|
||||
{ timeout: 60000 }
|
||||
);
|
||||
|
||||
// Additional wait for any rendering/animations to settle
|
||||
await page.waitForTimeout(500);
|
||||
});
|
||||
|
||||
// Helper function to create a test zone programmatically
|
||||
// Uses BFS to select a contiguous set of land cells for stable, representative testing
|
||||
async function createTestZone(page: any): Promise<number> {
|
||||
return await page.evaluate(() => {
|
||||
const { cells, zones } = (window as any).pack;
|
||||
|
||||
// Find a starting land cell (height >= 20)
|
||||
const totalCells = cells.i.length;
|
||||
let startCell = -1;
|
||||
for (let i = 1; i < totalCells; i++) {
|
||||
if (cells.h[i] >= 20) {
|
||||
startCell = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startCell === -1) {
|
||||
throw new Error("No land cells found to create a test zone");
|
||||
}
|
||||
|
||||
// Use BFS to select a contiguous set of 10-20 land cells
|
||||
const zoneCells: number[] = [];
|
||||
const visited = new Set<number>();
|
||||
const queue: number[] = [];
|
||||
|
||||
visited.add(startCell);
|
||||
queue.push(startCell);
|
||||
|
||||
while (queue.length > 0 && zoneCells.length < 20) {
|
||||
const current = queue.shift() as number;
|
||||
|
||||
// Only include land cells in the zone
|
||||
if (cells.h[current] >= 20) {
|
||||
zoneCells.push(current);
|
||||
}
|
||||
|
||||
// Explore neighbors
|
||||
const neighbors: number[] = cells.c[current] || [];
|
||||
for (const neighbor of neighbors) {
|
||||
if (neighbor && !visited.has(neighbor)) {
|
||||
visited.add(neighbor);
|
||||
queue.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneCells.length < 10) {
|
||||
throw new Error(`Not enough contiguous land cells found: ${zoneCells.length}`);
|
||||
}
|
||||
|
||||
// Generate unique zone ID
|
||||
const zoneId = zones.length;
|
||||
|
||||
// Create zone object
|
||||
const zone = {
|
||||
i: zoneId,
|
||||
name: "Test Export Zone",
|
||||
type: "Test",
|
||||
color: "#FF0000",
|
||||
cells: zoneCells,
|
||||
};
|
||||
|
||||
// Add zone to pack.zones array
|
||||
zones.push(zone);
|
||||
|
||||
return zoneId;
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to export zones to GeoJSON without file download
|
||||
// This calls the production code from public/modules/io/export.js
|
||||
async function exportZonesToGeoJson(page: any): Promise<any> {
|
||||
return await page.evaluate(() => {
|
||||
// Mock downloadFile to capture the JSON instead of downloading
|
||||
const originalDownloadFile = (window as any).downloadFile;
|
||||
let capturedJson: any = null;
|
||||
|
||||
(window as any).downloadFile = (data: string) => {
|
||||
capturedJson = JSON.parse(data);
|
||||
};
|
||||
|
||||
// Call the production code
|
||||
(window as any).saveGeoJsonZones();
|
||||
|
||||
// Restore original downloadFile
|
||||
(window as any).downloadFile = originalDownloadFile;
|
||||
|
||||
return capturedJson;
|
||||
});
|
||||
}
|
||||
|
||||
test("should export zone with valid GeoJSON root structure", async ({ page }) => {
|
||||
// Create a test zone
|
||||
const zoneId = await createTestZone(page);
|
||||
expect(zoneId).toBeGreaterThanOrEqual(0);
|
||||
|
||||
// Export zones to GeoJSON
|
||||
const geoJson = await exportZonesToGeoJson(page);
|
||||
|
||||
// Validate root GeoJSON structure (Task 5.1)
|
||||
expect(geoJson).toBeDefined();
|
||||
expect(geoJson).toHaveProperty("type");
|
||||
expect(geoJson.type).toBe("FeatureCollection");
|
||||
|
||||
expect(geoJson).toHaveProperty("features");
|
||||
expect(Array.isArray(geoJson.features)).toBe(true);
|
||||
expect(geoJson.features.length).toBeGreaterThan(0);
|
||||
|
||||
// Verify the test zone is in the export
|
||||
const testZoneFeature = geoJson.features.find((f: any) => f.properties.id === zoneId);
|
||||
expect(testZoneFeature).toBeDefined();
|
||||
expect(testZoneFeature.properties.name).toBe("Test Export Zone");
|
||||
|
||||
// Validate Feature structure (Task 5.2)
|
||||
expect(testZoneFeature).toHaveProperty("type");
|
||||
expect(testZoneFeature.type).toBe("Feature");
|
||||
|
||||
expect(testZoneFeature).toHaveProperty("geometry");
|
||||
expect(testZoneFeature.geometry).toBeDefined();
|
||||
expect(typeof testZoneFeature.geometry).toBe("object");
|
||||
|
||||
expect(testZoneFeature.geometry).toHaveProperty("type");
|
||||
// Note: Geometry type can be "Polygon" (single component) or "MultiPolygon" (multiple disconnected components)
|
||||
// For this test with contiguous BFS-selected cells, we expect "Polygon"
|
||||
expect(testZoneFeature.geometry.type).toBe("Polygon");
|
||||
|
||||
expect(testZoneFeature.geometry).toHaveProperty("coordinates");
|
||||
expect(Array.isArray(testZoneFeature.geometry.coordinates)).toBe(true);
|
||||
|
||||
expect(testZoneFeature).toHaveProperty("properties");
|
||||
expect(testZoneFeature.properties).toBeDefined();
|
||||
expect(typeof testZoneFeature.properties).toBe("object");
|
||||
|
||||
// Task 6.1: Validate zone property mapping
|
||||
// Get the test zone from pack.zones in browser context
|
||||
const testZone = await page.evaluate((id: number) => {
|
||||
const { zones } = (window as any).pack;
|
||||
return zones.find((z: any) => z.i === id);
|
||||
}, zoneId);
|
||||
|
||||
expect(testZone).toBeDefined();
|
||||
|
||||
// Assert feature.properties match zone properties
|
||||
expect(testZoneFeature.properties.id).toBe(testZone.i);
|
||||
expect(testZoneFeature.properties.name).toBe(testZone.name);
|
||||
expect(testZoneFeature.properties.type).toBe(testZone.type);
|
||||
expect(testZoneFeature.properties.color).toBe(testZone.color);
|
||||
expect(testZoneFeature.properties.cells).toEqual(testZone.cells);
|
||||
|
||||
// Task 7.1: Validate coordinate array structure
|
||||
const { coordinates } = testZoneFeature.geometry;
|
||||
|
||||
// Assert geometry.coordinates is an array
|
||||
expect(Array.isArray(coordinates)).toBe(true);
|
||||
|
||||
// Assert coordinates array is not empty
|
||||
expect(coordinates.length).toBeGreaterThan(0);
|
||||
|
||||
// Validate each LinearRing in the coordinates array
|
||||
// Note: Zones can have multiple rings (holes) or be MultiPolygon (disconnected components)
|
||||
for (const linearRing of coordinates) {
|
||||
// Assert LinearRing is an array
|
||||
expect(Array.isArray(linearRing)).toBe(true);
|
||||
|
||||
// Task 7.2: Validate LinearRing validity
|
||||
// Assert LinearRing has at least 4 positions
|
||||
expect(linearRing.length).toBeGreaterThanOrEqual(4);
|
||||
|
||||
// Assert first position equals last position (closed ring)
|
||||
const firstPosition = linearRing[0];
|
||||
const lastPosition = linearRing[linearRing.length - 1];
|
||||
expect(firstPosition[0]).toBe(lastPosition[0]);
|
||||
expect(firstPosition[1]).toBe(lastPosition[1]);
|
||||
|
||||
// Assert each position in LinearRing is an array of 2 numbers
|
||||
for (const position of linearRing) {
|
||||
expect(Array.isArray(position)).toBe(true);
|
||||
expect(position.length).toBe(2);
|
||||
expect(typeof position[0]).toBe("number");
|
||||
expect(typeof position[1]).toBe("number");
|
||||
|
||||
// Assert all positions are valid [longitude, latitude] pairs
|
||||
// Longitude should be between -180 and 180
|
||||
expect(position[0]).toBeGreaterThanOrEqual(-180);
|
||||
expect(position[0]).toBeLessThanOrEqual(180);
|
||||
|
||||
// Latitude should be between -90 and 90
|
||||
expect(position[1]).toBeGreaterThanOrEqual(-90);
|
||||
expect(position[1]).toBeLessThanOrEqual(90);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("should exclude hidden zones from GeoJSON export", async ({ page }) => {
|
||||
// Create a regular test zone
|
||||
const regularZoneId = await createTestZone(page);
|
||||
expect(regularZoneId).toBeGreaterThanOrEqual(0);
|
||||
|
||||
// Create a hidden zone
|
||||
const hiddenZoneId = await page.evaluate(() => {
|
||||
const { cells, zones } = (window as any).pack;
|
||||
|
||||
// Find a starting land cell that's not already in a zone
|
||||
const totalCells = cells.i.length;
|
||||
let startCell = -1;
|
||||
for (let i = 1; i < totalCells; i++) {
|
||||
const isLand = cells.h[i] >= 20;
|
||||
const notInZone = !zones.some((z: any) => z.cells && z.cells.includes(i));
|
||||
if (isLand && notInZone) {
|
||||
startCell = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startCell === -1) {
|
||||
throw new Error("No available land cells found for hidden zone");
|
||||
}
|
||||
|
||||
// Use BFS to select a contiguous set of 10-20 land cells
|
||||
const zoneCells: number[] = [];
|
||||
const visited = new Set<number>();
|
||||
const queue: number[] = [];
|
||||
|
||||
visited.add(startCell);
|
||||
queue.push(startCell);
|
||||
|
||||
while (queue.length > 0 && zoneCells.length < 20) {
|
||||
const current = queue.shift() as number;
|
||||
|
||||
// Only include land cells not already in a zone
|
||||
const isLand = cells.h[current] >= 20;
|
||||
const notInZone = !zones.some((z: any) => z.cells && z.cells.includes(current));
|
||||
if (isLand && notInZone) {
|
||||
zoneCells.push(current);
|
||||
}
|
||||
|
||||
// Explore neighbors
|
||||
const neighbors: number[] = cells.c[current] || [];
|
||||
for (const neighbor of neighbors) {
|
||||
if (neighbor && !visited.has(neighbor)) {
|
||||
visited.add(neighbor);
|
||||
queue.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneCells.length < 10) {
|
||||
throw new Error(`Not enough contiguous land cells found: ${zoneCells.length}`);
|
||||
}
|
||||
|
||||
// Generate unique zone ID
|
||||
const zoneId = zones.length;
|
||||
|
||||
// Create hidden zone object
|
||||
const zone = {
|
||||
i: zoneId,
|
||||
name: "Hidden Test Zone",
|
||||
type: "Test",
|
||||
color: "#00FF00",
|
||||
cells: zoneCells,
|
||||
hidden: true, // Mark as hidden
|
||||
};
|
||||
|
||||
// Add zone to pack.zones array
|
||||
zones.push(zone);
|
||||
|
||||
return zoneId;
|
||||
});
|
||||
expect(hiddenZoneId).toBeGreaterThanOrEqual(0);
|
||||
|
||||
// Export zones to GeoJSON
|
||||
const geoJson = await exportZonesToGeoJson(page);
|
||||
|
||||
// Validate that the regular zone is in the export
|
||||
const regularZoneFeature = geoJson.features.find((f: any) => f.properties.id === regularZoneId);
|
||||
expect(regularZoneFeature).toBeDefined();
|
||||
expect(regularZoneFeature.properties.name).toBe("Test Export Zone");
|
||||
|
||||
// Validate that the hidden zone is NOT in the export
|
||||
const hiddenZoneFeature = geoJson.features.find((f: any) => f.properties.id === hiddenZoneId);
|
||||
expect(hiddenZoneFeature).toBeUndefined();
|
||||
});
|
||||
|
||||
test("should exclude zones with empty cells array from GeoJSON export", async ({ page }) => {
|
||||
// Create a regular test zone
|
||||
const regularZoneId = await createTestZone(page);
|
||||
expect(regularZoneId).toBeGreaterThanOrEqual(0);
|
||||
|
||||
// Create a zone with empty cells array
|
||||
const emptyZoneId = await page.evaluate(() => {
|
||||
const { zones } = (window as any).pack;
|
||||
|
||||
// Generate unique zone ID
|
||||
const zoneId = zones.length;
|
||||
|
||||
// Create zone object with empty cells array
|
||||
const zone = {
|
||||
i: zoneId,
|
||||
name: "Empty Test Zone",
|
||||
type: "Test",
|
||||
color: "#0000FF",
|
||||
cells: [], // Empty cells array
|
||||
};
|
||||
|
||||
// Add zone to pack.zones array
|
||||
zones.push(zone);
|
||||
|
||||
return zoneId;
|
||||
});
|
||||
expect(emptyZoneId).toBeGreaterThanOrEqual(0);
|
||||
|
||||
// Export zones to GeoJSON
|
||||
const geoJson = await exportZonesToGeoJson(page);
|
||||
|
||||
// Validate that the regular zone is in the export
|
||||
const regularZoneFeature = geoJson.features.find((f: any) => f.properties.id === regularZoneId);
|
||||
expect(regularZoneFeature).toBeDefined();
|
||||
expect(regularZoneFeature.properties.name).toBe("Test Export Zone");
|
||||
|
||||
// Validate that the empty zone is NOT in the export
|
||||
const emptyZoneFeature = geoJson.features.find((f: any) => f.properties.id === emptyZoneId);
|
||||
expect(emptyZoneFeature).toBeUndefined();
|
||||
});
|
||||
});
|
||||
174
tests/fixtures/demo.map
vendored
Normal file
174
tests/fixtures/demo.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue