115 lines
4.0 KiB
JavaScript
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/);
|
|
});
|