Files
NODEDC_DESIGN_GUIDELINE/scripts/map-search.test.mjs
T

115 lines
4.0 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { readFile } from "node:fs/promises";
import { buildMapSearchIndex, searchMapSubjects } from "../apps/catalog/src/mapSearch.mjs";
const now = "2026-07-25T08:00:00.000Z";
const point = (sourceId, semanticType, attributes) => ({
sourceId,
semanticType,
observedAt: now,
receivedAt: now,
attributes,
geometry: { type: "Point", coordinates: [37.62, 55.75] },
presentationStatus: "active",
});
const profile = {
id: "map.subject.v1",
title: "Транспорт",
semanticTypes: ["map.moving_object"],
label: { mode: "attributes", fields: ["display_name"] },
};
test("search index uses stable identity, label and explicit field projection only", () => {
const index = buildMapSearchIndex({
runtimeBindings: [{
bindingId: "vehicles",
presentationProfileId: profile.id,
facts: [point("unit-42", "map.moving_object", {
display_name: "Трайк 42",
tracker_id: "tracker-77",
raw_secret: "must-not-be-indexed",
})],
}],
bindingConfigs: [{
id: "vehicles",
fieldProjection: ["display_name", "tracker_id"],
presentationProfileId: profile.id,
}],
presentationProfiles: [profile],
});
assert.equal(searchMapSubjects(index, "Трайк").at(0)?.sourceId, "unit-42");
assert.equal(searchMapSubjects(index, "tracker-77").at(0)?.sourceId, "unit-42");
assert.equal(searchMapSubjects(index, "unit-42").at(0)?.sourceId, "unit-42");
assert.deepEqual(searchMapSubjects(index, "must-not-be-indexed"), []);
});
test("authorized joined aspect augments primary subject without creating a second entity", () => {
const index = buildMapSearchIndex({
runtimeBindings: [
{
bindingId: "vehicles",
presentationProfileId: profile.id,
facts: [point("unit-42", "map.moving_object", { display_name: "Трайк 42" })],
},
{
bindingId: "identity",
facts: [point("unit-42", "map.moving_object", {
imei: "867236078012345",
provider_payload: "forbidden",
})],
},
],
bindingConfigs: [
{ id: "vehicles", fieldProjection: ["display_name"], presentationProfileId: profile.id },
{
id: "identity",
joinToBindingId: "vehicles",
fieldProjection: ["imei"],
dataClass: "restricted",
},
],
presentationProfiles: [profile],
});
assert.equal(index.length, 1);
assert.equal(searchMapSubjects(index, "867236078012345").at(0)?.entityId, "nodedc-runtime:vehicles:map.moving_object:unit-42");
assert.deepEqual(searchMapSubjects(index, "forbidden"), []);
});
test("reference subjects remain searchable by profile labels without a provider branch", () => {
const stationProfile = {
id: "map.reference.station.v1",
title: "Метро",
semanticTypes: ["map.station"],
label: { mode: "attributes", fields: ["name", "official_name"] },
};
const index = buildMapSearchIndex({
runtimeBindings: [{
bindingId: "reference.metro",
presentationProfileId: stationProfile.id,
facts: [point("osm.node.1", "map.station", {
name: "Петроградская",
provider_note: "not searchable",
})],
}],
presentationProfiles: [stationProfile],
});
assert.equal(searchMapSubjects(index, "петрог").at(0)?.title, "Петроградская");
assert.equal(searchMapSubjects(index, "osm.node.1").at(0)?.groupTitle, "Метро");
assert.deepEqual(searchMapSubjects(index, "provider_note"), []);
});
test("expanded search keeps the canonical toolbar inset on every edge", async () => {
const styles = await readFile(new URL("../apps/catalog/src/styles.css", import.meta.url), "utf8");
const baseToolbar = styles.match(/\.catalog-map-fixture__toolbar\s*\{(?<body>[\s\S]*?)\n\}/)?.groups?.body ?? "";
const expandedToolbar = styles.match(/\.catalog-map-fixture__toolbar\[data-search-open\]\s*\{(?<body>[\s\S]*?)\n\}/)?.groups?.body ?? "";
assert.match(baseToolbar, /padding: 0\.4rem/);
assert.doesNotMatch(expandedToolbar, /padding-right:\s*0/);
});