mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
test(mapillary): provider, source, presentation, markup and QA-harness coverage
scripts/qa-mapillary.mjs drives a real browser through the rail panel, the keyless gate, coverage, a ready-made feature plan, the viewer and its expanded dialog at 1440×900 and 1280×800. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
70ebdeb783
commit
f6f8fd8fa8
11 files changed
+1558
-97
No files matched your search
@@ -0,0 +1,236 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
mapillaryImageUrl,
|
||||
presentMapillaryPanel,
|
||||
} from './mapillaryPresentation.js';
|
||||
|
||||
function snapshot(overrides = {}) {
|
||||
const base = {
|
||||
enabled: false,
|
||||
keyRequired: false,
|
||||
planner: true,
|
||||
plannerModel: 'claude-opus-5',
|
||||
coverage: {
|
||||
zoom: null,
|
||||
kind: null,
|
||||
filter: { pano: 'all', sinceMs: null },
|
||||
legend: [
|
||||
{ key: 'recent', label: 'Recent (≤2 yr)', color: '#05cb63' },
|
||||
{ key: 'older', label: 'Older', color: '#2e7d5b' },
|
||||
{ key: 'pano', label: '360°', color: '#ff4fd8' },
|
||||
{ key: 'selected', label: 'Selected', color: '#00d4ff' },
|
||||
],
|
||||
loading: false,
|
||||
sequences: 0,
|
||||
hint: '',
|
||||
error: null,
|
||||
},
|
||||
sequence: { selectedId: null, images: 0, loading: false },
|
||||
features: {
|
||||
total: 0,
|
||||
title: '',
|
||||
loading: false,
|
||||
progress: { done: 0, tiles: 0 },
|
||||
counts: [],
|
||||
truncated: false,
|
||||
failed: 0,
|
||||
iconMode: false,
|
||||
hasBbox: false,
|
||||
selectedId: null,
|
||||
bbox: null,
|
||||
},
|
||||
street: {
|
||||
open: false,
|
||||
follow: false,
|
||||
loading: false,
|
||||
error: null,
|
||||
imageId: null,
|
||||
position: null,
|
||||
bearing: null,
|
||||
isPano: false,
|
||||
capturedAt: null,
|
||||
sequenceId: null,
|
||||
creator: null,
|
||||
renderMode: 'letterbox',
|
||||
feature: null,
|
||||
highlight: null,
|
||||
},
|
||||
query: {
|
||||
busy: false,
|
||||
stage: 'idle',
|
||||
prompt: '',
|
||||
place: null,
|
||||
answer: '',
|
||||
error: null,
|
||||
title: '',
|
||||
usage: null,
|
||||
history: [],
|
||||
},
|
||||
};
|
||||
return deepMerge(base, overrides);
|
||||
}
|
||||
|
||||
function deepMerge(target, source) {
|
||||
const out = { ...target };
|
||||
for (const [key, value] of Object.entries(source)) {
|
||||
out[key] =
|
||||
value &&
|
||||
typeof value === 'object' &&
|
||||
!Array.isArray(value) &&
|
||||
target[key] &&
|
||||
typeof target[key] === 'object'
|
||||
? deepMerge(target[key], value)
|
||||
: value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
test('a missing Mapillary token gates every control and names the variable', () => {
|
||||
const view = presentMapillaryPanel(snapshot({ keyRequired: true }));
|
||||
assert.equal(view.keyless.visible, true);
|
||||
assert.match(view.keyless.text, /MAPILLARY_CLIENT_TOKEN/);
|
||||
assert.equal(view.controlsDisabled, true);
|
||||
assert.deepEqual(view.status, { text: 'KEY REQUIRED', tone: 'warn' });
|
||||
});
|
||||
|
||||
test('without an Anthropic key the query box explains itself and stays disabled', () => {
|
||||
const view = presentMapillaryPanel(
|
||||
snapshot({ planner: false, enabled: true }),
|
||||
);
|
||||
assert.equal(view.query.inputDisabled, true);
|
||||
assert.equal(view.query.suggestionsDisabled, true);
|
||||
assert.equal(view.query.hintWarn, true);
|
||||
assert.match(view.query.hint, /Anthropic key/);
|
||||
assert.ok(view.query.placeholder.length < 40, 'placeholder fits the field');
|
||||
assert.equal(view.keyless.visible, false);
|
||||
assert.equal(view.controlsDisabled, false);
|
||||
});
|
||||
|
||||
test('a running query turns ASK into STOP and shows indeterminate progress per stage', () => {
|
||||
const planning = presentMapillaryPanel(
|
||||
snapshot({ enabled: true, query: { busy: true, stage: 'planning' } }),
|
||||
);
|
||||
assert.equal(planning.query.submitLabel, 'STOP');
|
||||
assert.equal(planning.query.submitIsStop, true);
|
||||
assert.deepEqual(planning.progress, {
|
||||
visible: true,
|
||||
indeterminate: true,
|
||||
percent: 0,
|
||||
label: 'Planning…',
|
||||
});
|
||||
assert.equal(planning.status.text, 'AI · PLANNING');
|
||||
|
||||
const resolving = presentMapillaryPanel(
|
||||
snapshot({
|
||||
enabled: true,
|
||||
query: { busy: true, stage: 'resolving', place: 'Sacramento, CA' },
|
||||
}),
|
||||
);
|
||||
assert.equal(resolving.progress.label, 'Finding Sacramento, CA…');
|
||||
|
||||
const fetching = presentMapillaryPanel(
|
||||
snapshot({
|
||||
enabled: true,
|
||||
query: { busy: true, stage: 'fetching' },
|
||||
features: { loading: true, progress: { done: 3, tiles: 12 }, total: 410 },
|
||||
}),
|
||||
);
|
||||
assert.equal(fetching.progress.indeterminate, false);
|
||||
assert.equal(fetching.progress.percent, 25);
|
||||
assert.equal(fetching.progress.label, '3/12 tiles · 410 found');
|
||||
});
|
||||
|
||||
test('idle copy depends on whether the layer is on', () => {
|
||||
assert.match(
|
||||
presentMapillaryPanel(snapshot()).answer,
|
||||
/Turn on Street Level/,
|
||||
);
|
||||
assert.match(
|
||||
presentMapillaryPanel(snapshot({ enabled: true })).answer,
|
||||
/Click a green line/,
|
||||
);
|
||||
const view = presentMapillaryPanel(
|
||||
snapshot({ enabled: true, query: { error: 'Planner unavailable' } }),
|
||||
);
|
||||
assert.equal(view.error, 'Planner unavailable');
|
||||
assert.equal(view.answer, '');
|
||||
});
|
||||
|
||||
test('result chips cap at eight and describe the overflow', () => {
|
||||
const counts = Array.from({ length: 11 }, (_, i) => ({
|
||||
value: `object--v${i}`,
|
||||
label: `Class ${i}`,
|
||||
color: '#fff',
|
||||
count: 100 - i,
|
||||
}));
|
||||
const view = presentMapillaryPanel(
|
||||
snapshot({ enabled: true, features: { total: 900, counts } }),
|
||||
);
|
||||
assert.equal(view.results.visible, true);
|
||||
assert.equal(view.results.chips.length, 8);
|
||||
assert.equal(view.results.more.count, 3);
|
||||
assert.match(view.results.more.title, /Class 8 92, Class 9 91, Class 10 90/);
|
||||
assert.equal(view.results.all.length, 11);
|
||||
});
|
||||
|
||||
test('legend passes through in the layer’s order', () => {
|
||||
const view = presentMapillaryPanel(snapshot());
|
||||
assert.deepEqual(
|
||||
view.legend.map((entry) => entry.key),
|
||||
['recent', 'older', 'pano', 'selected'],
|
||||
);
|
||||
});
|
||||
|
||||
test('the meta line never mixes the visible-sequence count with the selected sequence', () => {
|
||||
const browsing = presentMapillaryPanel(
|
||||
snapshot({ enabled: true, coverage: { zoom: 14, sequences: 812 } }),
|
||||
);
|
||||
assert.match(browsing.meta, /^812 sequences in view · click a line/);
|
||||
const selected = presentMapillaryPanel(
|
||||
snapshot({
|
||||
enabled: true,
|
||||
coverage: { zoom: 14, sequences: 812 },
|
||||
sequence: { selectedId: 'abc', images: 33 },
|
||||
}),
|
||||
);
|
||||
assert.equal(selected.meta, '33 images in this sequence · Esc clears');
|
||||
assert.doesNotMatch(selected.meta, /sequences in view/);
|
||||
});
|
||||
|
||||
test('viewer caption reads "Image by" left and date right, with a deep link', () => {
|
||||
const view = presentMapillaryPanel(
|
||||
snapshot({
|
||||
enabled: true,
|
||||
street: {
|
||||
open: true,
|
||||
imageId: '1814275685699406',
|
||||
creator: 'mapfool',
|
||||
capturedAt: Date.UTC(2023, 9, 8),
|
||||
bearing: 93.4,
|
||||
isPano: true,
|
||||
feature: { label: 'Fire hydrant', imageCount: 5 },
|
||||
highlight: { count: 2 },
|
||||
},
|
||||
}),
|
||||
);
|
||||
assert.equal(
|
||||
view.viewer.captionLeft,
|
||||
'Fire hydrant · 5 sightings · 2 detections outlined · Image by mapfool',
|
||||
);
|
||||
assert.equal(view.viewer.captionRight, '360° · 93° · 2023-10-08');
|
||||
assert.equal(
|
||||
view.viewer.link,
|
||||
'https://www.mapillary.com/app/?pKey=1814275685699406&focus=photo',
|
||||
);
|
||||
assert.equal(view.viewer.follow.disabled, false);
|
||||
assert.equal(view.wantsOpen, true);
|
||||
});
|
||||
|
||||
test('image deep links match the mapillary.com share format', () => {
|
||||
assert.equal(
|
||||
mapillaryImageUrl(1814275685699406),
|
||||
'https://www.mapillary.com/app/?pKey=1814275685699406&focus=photo',
|
||||
);
|
||||
assert.equal(mapillaryImageUrl(' '), 'https://www.mapillary.com/app/');
|
||||
});
|
||||
Reference in new issue
Block a user