mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
fix(street-level): IC8 review of the Street View provider
Google's Maps Platform terms forbid Street View imagery beside non-Google maps, so the provider declares requiresMapStack: 'photoreal': off Google 3D its chip is dashed with the reason, lookups and opens skip it, and leaving Google 3D closes its panorama. - Ground clicks: only a click on the map itself (scenePick.isSurfacePick: nothing picked or Google 3D tile content) at street zoom opens Street View, and the camera stays put; higher up the hint says to zoom in. scenePick.pickGroundPosition replaces the copy in Directions. - Viewer: poses go out at once and again when the date and address arrive, so an open never hangs on that lookup; one lookup per panorama, seeded by the nearest lookup; a close settles a pending open; failed lookups are asked again; poses follow position changes, not pano_changed. - Loader: the gm_authFailure handler is installed once, so a retried load reports a refusal once. - Viewer host: a prewarm that lands after another provider took the host is released; FIT/FILL availability is set on every open. - Provider: a refusal while switched off reports no error over another photo; SINCE compares against the end of Google's month; messages name the referrer and network causes; FLAT says Street View is 360° only. - The layer row names the key of the providers that are on; the MCP panel CSP admits Street View's tiles, control images and photos. - Tests for each, against fakes that now follow Google's event order; the browser gate restores its state, waits instead of sleeping, aims its panel clicks and corner drags, and asserts the camera stays put. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
22b0009138
commit
7bfcf177ac
35 files changed
+1108
-388
No files matched your search
@@ -153,7 +153,128 @@ test('a key Google refuses fails the open at once, not after the timeout', async
|
||||
panorama.pano = id;
|
||||
queueMicrotask(() => loader.refuseKey());
|
||||
};
|
||||
await assert.rejects(viewer.open('pano-a'), /enable the Maps JavaScript API/);
|
||||
await assert.rejects(viewer.open('pano-b'), /enable the Maps JavaScript API/);
|
||||
await assert.rejects(viewer.open('pano-a'), /Maps JavaScript API is enabled/);
|
||||
await assert.rejects(viewer.open('pano-b'), /Maps JavaScript API is enabled/);
|
||||
assert.equal(loader.listenerCount(), 0, 'no auth listener is left behind');
|
||||
});
|
||||
|
||||
test('a viewer unmounted while the library loads builds no panorama (none is billed)', async () => {
|
||||
const fake = fakeStreetViewLibrary({ panoramas: PANORAMAS });
|
||||
const loader = fakeMapsLoader(fake.library, { deferred: true });
|
||||
const viewer = createGoogleViewer({ loader });
|
||||
const host = fakeHost();
|
||||
const mounting = viewer.mount(host);
|
||||
viewer.unmount();
|
||||
loader.release();
|
||||
await assert.rejects(mounting, /unmounted/);
|
||||
assert.equal(fake.built.length, 0);
|
||||
assert.equal(host.children.length, 0);
|
||||
});
|
||||
|
||||
test('a date that arrives after the photo was closed emits nothing', async () => {
|
||||
const { fake, viewer, poses, host } = setup();
|
||||
await viewer.mount(host);
|
||||
await viewer.open('pano-a');
|
||||
const [panorama] = fake.built;
|
||||
let answer;
|
||||
fake.library.StreetViewService.prototype.getPanorama = () =>
|
||||
new Promise((resolve) => {
|
||||
answer = resolve;
|
||||
});
|
||||
panorama.setPano('pano-b'); // Google's arrow; its date is still unknown
|
||||
await settle();
|
||||
assert.equal(poses.at(-1).imageId, 'pano-b', 'the step shows at once');
|
||||
assert.equal(
|
||||
poses.at(-1).capturedAt,
|
||||
null,
|
||||
'undated until the lookup answers',
|
||||
);
|
||||
viewer.close();
|
||||
const count = poses.length;
|
||||
answer({ data: { imageDate: '2019-08' } });
|
||||
await settle();
|
||||
assert.equal(poses.length, count);
|
||||
});
|
||||
|
||||
test('an open never waits on the date lookup', async () => {
|
||||
const { fake, viewer, poses, host } = setup();
|
||||
await viewer.mount(host);
|
||||
fake.library.StreetViewService.prototype.getPanorama = () =>
|
||||
new Promise(() => {}); // the metadata never answers
|
||||
await viewer.open('pano-a');
|
||||
assert.equal(poses.at(-1).imageId, 'pano-a');
|
||||
});
|
||||
|
||||
test('closing while a panorama loads settles the open and drops its listeners', async () => {
|
||||
const { fake, loader, viewer, host } = setup();
|
||||
await viewer.mount(host);
|
||||
const [panorama] = fake.built;
|
||||
const before = panorama.listenerCount();
|
||||
panorama.setPano = (id) => {
|
||||
panorama.pano = id; // still loading
|
||||
};
|
||||
const opening = viewer.open('pano-a');
|
||||
await settle();
|
||||
viewer.close();
|
||||
await opening;
|
||||
assert.equal(panorama.listenerCount(), before);
|
||||
assert.equal(loader.listenerCount(), 0);
|
||||
});
|
||||
|
||||
test('a second open whose status stays OK still resolves, on the new position', async () => {
|
||||
const { fake, viewer, poses, host } = setup();
|
||||
await viewer.mount(host);
|
||||
await viewer.open('pano-a');
|
||||
assert.equal(fake.built[0].getStatus(), 'OK');
|
||||
await viewer.open('pano-b'); // OK → OK: no status_changed
|
||||
assert.equal(poses.at(-1).imageId, 'pano-b');
|
||||
});
|
||||
|
||||
test('Google answering with a newer id for the place shows that id', async () => {
|
||||
const fake = fakeStreetViewLibrary({
|
||||
panoramas: PANORAMAS,
|
||||
substitutes: { 'old-id': 'pano-a' },
|
||||
});
|
||||
const viewer = createGoogleViewer({ loader: fakeMapsLoader(fake.library) });
|
||||
const poses = [];
|
||||
viewer.onPose((pose) => poses.push(pose));
|
||||
await viewer.mount(fakeHost());
|
||||
await viewer.open('old-id');
|
||||
assert.equal(poses.at(-1).imageId, 'pano-a');
|
||||
});
|
||||
|
||||
test('a panorama that never shows fails after the timeout and leaves no listener', async (t) => {
|
||||
t.mock.timers.enable({ apis: ['setTimeout'] });
|
||||
const { OPEN_TIMEOUT_MS, NO_ANSWER_MESSAGE } = await import('./policy.js');
|
||||
const { fake, loader, viewer, host } = setup();
|
||||
await viewer.mount(host);
|
||||
const [panorama] = fake.built;
|
||||
const before = panorama.listenerCount();
|
||||
panorama.setPano = (id) => {
|
||||
panorama.pano = id; // Google never answers
|
||||
};
|
||||
const opening = viewer.open('pano-a');
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
t.mock.timers.tick(OPEN_TIMEOUT_MS);
|
||||
await assert.rejects(opening, { message: NO_ANSWER_MESSAGE });
|
||||
assert.equal(panorama.listenerCount(), before);
|
||||
assert.equal(loader.listenerCount(), 0);
|
||||
});
|
||||
|
||||
test('a date lookup that failed is asked again on the next view change', async () => {
|
||||
const { fake, viewer, poses, host } = setup();
|
||||
await viewer.mount(host);
|
||||
const getPanorama = fake.library.StreetViewService.prototype.getPanorama;
|
||||
let failures = 1;
|
||||
fake.library.StreetViewService.prototype.getPanorama = function (request) {
|
||||
if (failures-- > 0) return Promise.reject(new Error('offline'));
|
||||
return getPanorama.call(this, request);
|
||||
};
|
||||
await viewer.open('pano-a');
|
||||
assert.equal(poses.at(-1).capturedAt, null, 'undated while it failed');
|
||||
fake.built[0].setPov({ heading: 10, pitch: 0 });
|
||||
await settle();
|
||||
await settle();
|
||||
assert.equal(poses.at(-1).capturedAt, Date.UTC(2024, 4, 1));
|
||||
});
|
||||
Reference in new issue
Block a user