mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
- An open after a failed one is no longer failed by the old panorama's status: only status_changed can reject; position_changed only resolves. - A nearest lookup aborted, timed out or refused while Google's script loads no longer sends its getPanorama request once the script arrives. - A panorama-details lookup that never answers times out after 10 s, cools down and retries; an unmount releases lookups in flight, and their late answers are dropped. - Every Maps loader on a page shares one script load and ready callback, and either can retry a failed script. - OPEN STREET VIEW aimed at the sky opens nothing and says to aim at a street, instead of looking up the camera footprint. Co-Authored-By: Claude Opus 5.5 <[email protected]>
145 lines
5.3 KiB
JavaScript
145 lines
5.3 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createMapsLoader } from './mapsLoader.js';
|
|
|
|
/** A document whose appended scripts the test loads or fails. */
|
|
function fakePage() {
|
|
const scripts = [];
|
|
const document = {
|
|
createElement: () => {
|
|
const script = {
|
|
remove() {
|
|
scripts.splice(scripts.indexOf(script), 1);
|
|
},
|
|
};
|
|
return script;
|
|
},
|
|
head: { append: (script) => scripts.push(script) },
|
|
};
|
|
const global = {};
|
|
const library = { name: 'streetView' };
|
|
/** Google's script arrived: it defines google.maps and calls back. */
|
|
const loadScript = () => {
|
|
global.google = {
|
|
maps: { importLibrary: async (name) => ({ ...library, name }) },
|
|
};
|
|
const callback = new URL(scripts.at(-1).src).searchParams.get('callback');
|
|
global[callback]();
|
|
};
|
|
return { document, global, scripts, loadScript };
|
|
}
|
|
|
|
const settle = () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
|
|
test('the API loads once, with the key, asynchronously, and hands out libraries', async () => {
|
|
const page = fakePage();
|
|
const loader = createMapsLoader({ getApiKey: () => 'k-1', ...page });
|
|
const first = loader.importLibrary('streetView');
|
|
const second = loader.importLibrary('streetView');
|
|
await settle();
|
|
assert.equal(page.scripts.length, 1, 'one script for concurrent imports');
|
|
const url = new URL(page.scripts[0].src);
|
|
assert.equal(
|
|
url.origin + url.pathname,
|
|
'https://maps.googleapis.com/maps/api/js',
|
|
);
|
|
assert.equal(url.searchParams.get('key'), 'k-1');
|
|
assert.equal(url.searchParams.get('loading'), 'async');
|
|
assert.equal(page.scripts[0].async, true);
|
|
page.loadScript();
|
|
assert.equal((await first).name, 'streetView');
|
|
assert.equal((await second).name, 'streetView');
|
|
const callback = url.searchParams.get('callback');
|
|
assert.equal(page.global[callback], undefined, 'the callback is cleaned up');
|
|
});
|
|
|
|
test('two loaders on one page share one script and both get the API', async () => {
|
|
const page = fakePage();
|
|
const first = createMapsLoader({ getApiKey: () => 'k', ...page });
|
|
const second = createMapsLoader({ getApiKey: () => 'k', ...page });
|
|
const one = first.importLibrary('streetView');
|
|
const two = second.importLibrary('streetView');
|
|
await settle();
|
|
assert.equal(page.scripts.length, 1, 'one script for the page');
|
|
page.loadScript();
|
|
assert.equal((await one).name, 'streetView');
|
|
assert.equal((await two).name, 'streetView');
|
|
assert.equal((await first.importLibrary('streetView')).name, 'streetView');
|
|
});
|
|
|
|
test('after a failed script, either loader on the page can retry it', async () => {
|
|
const page = fakePage();
|
|
const first = createMapsLoader({ getApiKey: () => 'k', ...page });
|
|
const second = createMapsLoader({ getApiKey: () => 'k', ...page });
|
|
const failed = first.importLibrary('streetView');
|
|
await settle();
|
|
page.scripts[0].onerror();
|
|
await assert.rejects(failed, /could not load/);
|
|
const retry = second.importLibrary('streetView');
|
|
const again = first.importLibrary('streetView');
|
|
await settle();
|
|
assert.equal(page.scripts.length, 1);
|
|
page.loadScript();
|
|
assert.equal((await retry).name, 'streetView');
|
|
assert.equal((await again).name, 'streetView');
|
|
});
|
|
|
|
test('without a key nothing loads', async () => {
|
|
const page = fakePage();
|
|
const loader = createMapsLoader({ getApiKey: () => null, ...page });
|
|
await assert.rejects(loader.importLibrary('streetView'), /not set/);
|
|
assert.equal(page.scripts.length, 0);
|
|
});
|
|
|
|
test('a script that fails to load can be retried', async () => {
|
|
const page = fakePage();
|
|
const loader = createMapsLoader({ getApiKey: () => 'k', ...page });
|
|
const failed = loader.importLibrary('streetView');
|
|
await settle();
|
|
page.scripts[0].onerror();
|
|
await assert.rejects(failed, /could not load/);
|
|
assert.equal(page.scripts.length, 0, 'the failed script is removed');
|
|
const retry = loader.importLibrary('streetView');
|
|
await settle();
|
|
assert.equal(page.scripts.length, 1);
|
|
page.loadScript();
|
|
assert.equal((await retry).name, 'streetView');
|
|
});
|
|
|
|
test("Google's refusal of the key reaches every listener and the page's own handler", async () => {
|
|
const page = fakePage();
|
|
let before = 0;
|
|
page.global.gm_authFailure = () => before++;
|
|
const loader = createMapsLoader({ getApiKey: () => 'k', ...page });
|
|
const heard = [];
|
|
const stop = loader.onAuthFailure(() => heard.push('a'));
|
|
loader.importLibrary('streetView');
|
|
await settle();
|
|
assert.equal(loader.authFailed(), false);
|
|
page.global.gm_authFailure();
|
|
assert.equal(loader.authFailed(), true);
|
|
assert.deepEqual(heard, ['a']);
|
|
assert.equal(before, 1, 'a handler installed earlier still runs');
|
|
stop();
|
|
page.global.gm_authFailure();
|
|
assert.deepEqual(heard, ['a']);
|
|
});
|
|
|
|
test('a retried load still reports a refusal once, and the page handler once', async () => {
|
|
const page = fakePage();
|
|
let before = 0;
|
|
page.global.gm_authFailure = () => before++;
|
|
const loader = createMapsLoader({ getApiKey: () => 'k', ...page });
|
|
const heard = [];
|
|
loader.onAuthFailure(() => heard.push('a'));
|
|
const failed = loader.importLibrary('streetView');
|
|
await settle();
|
|
page.scripts[0].onerror();
|
|
await assert.rejects(failed);
|
|
loader.importLibrary('streetView');
|
|
await settle();
|
|
page.global.gm_authFailure();
|
|
assert.deepEqual(heard, ['a']);
|
|
assert.equal(before, 1);
|
|
});
|