@panoramax/web-viewer
Version:
Panoramax web viewer for geolocated pictures
444 lines (401 loc) • 12.9 kB
JavaScript
import URLHandler from "../../src/utils/URLHandler";
describe("listenToChanges", () => {
it("should add event listeners to window, parent, psv, and map", () => {
window.addEventListener = jest.fn();
const parent = {
addEventListener: jest.fn(),
psv: { addEventListener: jest.fn() },
map: { on: jest.fn() },
};
const urlHandler = new URLHandler(parent);
urlHandler.listenToChanges();
expect(window.addEventListener).toHaveBeenCalledWith("popstate", expect.any(Function), false);
["focus-changed", "pictures-navigation-changed"].forEach(event => {
expect(parent.addEventListener).toHaveBeenCalledWith(event, expect.any(Function));
});
["position-updated", "zoom-updated", "view-rotated", "picture-loaded", "transition-duration-changed"].forEach(event => {
expect(parent.psv.addEventListener).toHaveBeenCalledWith(event, expect.any(Function));
});
["moveend", "zoomend", "boxzoomend", "background-changed", "users-changed", "filters-changed"].forEach(event => {
expect(parent.map.on).toHaveBeenCalledWith(event, expect.any(Function));
});
});
});
describe("nextURLString", () => {
it("works without any specific values set", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => null,
getTransitionDuration: () => null,
getPictureMetadata: () => null,
getPictureId: () => null,
},
};
const uh = new URLHandler(v);
expect(uh.nextURLString()).toBe("?");
});
it("works with picture metadata", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => null,
getTransitionDuration: () => null,
getPictureMetadata: () => ({}),
getPictureId: () => "cbfc3add-8173-4464-98c8-de2a43c6a50f",
},
};
const uh = new URLHandler(v);
uh.currentPSVString = () => "0/1/2";
expect(uh.nextURLString()).toBe("?pic=cbfc3add-8173-4464-98c8-de2a43c6a50f&xyz=0/1/2");
});
it("works with map started + wide", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => null,
getTransitionDuration: () => null,
getPictureMetadata: () => null,
getPictureId: () => null,
},
map: {
getVisibleUsers: () => ["geovisio"],
hasTwoBackgrounds: () => false,
loaded: () => true,
},
isMapWide: () => true,
popup: { hasAttribute: () => false },
};
const uh = new URLHandler(v);
uh.currentMapString = () => "18/0.5/-12";
expect(uh.nextURLString()).toBe("?focus=map&map=18/0.5/-12");
});
it("works with map + picture wide", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => null,
getTransitionDuration: () => null,
getPictureMetadata: () => ({}),
getPictureId: () => "cbfc3add-8173-4464-98c8-de2a43c6a50f",
},
map: {
getVisibleUsers: () => ["geovisio"],
hasTwoBackgrounds: () => false,
loaded: () => true,
},
isMapWide: () => false,
popup: { hasAttribute: () => false },
};
const uh = new URLHandler(v);
uh.currentPSVString = () => "0/1/2";
uh.currentMapString = () => "18/0.5/-12";
expect(uh.nextURLString()).toBe("?focus=pic&map=18/0.5/-12&pic=cbfc3add-8173-4464-98c8-de2a43c6a50f&xyz=0/1/2");
});
it("works with map filters", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => null,
getTransitionDuration: () => null,
getPictureMetadata: () => null,
getPictureId: () => null,
},
map: {
getVisibleUsers: () => ["geovisio"],
hasTwoBackgrounds: () => false,
loaded: () => true,
_mapFilters: {
"minDate": "2023-01-01",
"maxDate": "2023-08-08",
"camera": "sony",
"pic_type": "flat",
"theme": "age",
},
},
isMapWide: () => false,
popup: { hasAttribute: () => false },
};
const uh = new URLHandler(v);
uh.currentMapString = () => "18/0.5/-12";
expect(uh.nextURLString()).toBe("?camera=sony&date_from=2023-01-01&date_to=2023-08-08&focus=pic&map=18/0.5/-12&pic_type=flat&theme=age");
});
it("works with speed", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => null,
getTransitionDuration: () => 250,
getPictureMetadata: () => null,
getPictureId: () => null,
},
};
const uh = new URLHandler(v);
expect(uh.nextURLString()).toBe("?speed=250");
});
it("works with popup", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => null,
getTransitionDuration: () => null,
getPictureMetadata: () => null,
getPictureId: () => null,
},
map: {
getVisibleUsers: () => ["geovisio"],
hasTwoBackgrounds: () => false,
loaded: () => true,
},
isMapWide: () => false,
popup: { hasAttribute: () => true },
};
const uh = new URLHandler(v);
uh.currentMapString = () => "18/0.5/-12";
expect(uh.nextURLString()).toBe("?focus=pic&map=18/0.5/-12");
});
it("works with nav", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getPicturesNavigation: () => "pic",
getTransitionDuration: () => null,
getPictureMetadata: () => null,
getPictureId: () => null,
},
};
const uh = new URLHandler(v);
expect(uh.nextURLString()).toBe("?nav=pic");
});
});
describe("currentURLParams", () => {
it("works if empty + search", () => {
delete window.location;
window.location = { search: "" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams()).toStrictEqual({});
});
it("works with single param + search", () => {
delete window.location;
window.location = { search: "?nav=pic" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams()).toStrictEqual({"nav": "pic"});
});
it("works with multiple params + search", () => {
delete window.location;
window.location = { search: "?nav=pic&speed=42" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams()).toStrictEqual({"nav": "pic", "speed": "42"});
});
it("works if empty + hash", () => {
delete window.location;
window.location = { hash: "" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams(true)).toStrictEqual({});
});
it("works with single param + hash", () => {
delete window.location;
window.location = { hash: "#nav=pic" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams(true)).toStrictEqual({"nav": "pic"});
});
it("works with multiple params + hash", () => {
delete window.location;
window.location = { hash: "#nav=pic&speed=42" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams(true)).toStrictEqual({"nav": "pic", "speed": "42"});
});
it("works with search + hash", () => {
delete window.location;
window.location = { hash: "#nav=pic&speed=42", search: "?pic=bla" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams()).toStrictEqual({"pic": "bla"});
expect(uh.currentURLParams(true)).toStrictEqual({"nav": "pic", "speed": "42"});
});
it("skips unmanaged parameters", () => {
delete window.location;
window.location = { search: "?a=b" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams()).toStrictEqual({});
});
it("works with shortlinks", () => {
delete window.location;
window.location = { search: "?s=fp;s2;pa0270208-d79d-49a9-85c7-a352bb96962e;c282.09/9.34/30;m17/43.107492/5.868459;va;bs" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams()).toStrictEqual({
"focus": "pic",
"speed": 200,
"pic": "a0270208-d79d-49a9-85c7-a352bb96962e",
"xyz": "282.09/9.34/30",
"map": "17/43.107492/5.868459",
"theme": "age",
"background": "streets",
"camera": undefined,
"date_from": undefined,
"date_to": undefined,
"pic_score": undefined,
"users": undefined
});
});
it("works with shortlinks urlEncoded", () => {
delete window.location;
window.location = { search: "?s=fp%3Bs2%3Bpa0270208-d79d-49a9-85c7-a352bb96962e%3Bc282.09/9.34/30%3Bm17/43.107492/5.868459%3Bva%3Bbs" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
expect(uh.currentURLParams()).toStrictEqual({
"focus": "pic",
"speed": 200,
"pic": "a0270208-d79d-49a9-85c7-a352bb96962e",
"xyz": "282.09/9.34/30",
"map": "17/43.107492/5.868459",
"theme": "age",
"background": "streets",
"camera": undefined,
"date_from": undefined,
"date_to": undefined,
"pic_score": undefined,
"users": undefined
});
});
});
describe("currentMapString", () => {
it("works with zoom+center", () => {
const v = {
addEventListener: jest.fn(),
map: {
getZoom: () => 18,
getCenter: () => ({ lng: -12.5, lat: 48.75 }),
getBearing: () => null,
getPitch: () => null,
}
};
const uh = new URLHandler(v);
expect(uh.currentMapString()).toBe("18/48.75/-12.5");
});
it("works with zoom+center+bearing", () => {
const v = {
addEventListener: jest.fn(),
map: {
getZoom: () => 18,
getCenter: () => ({ lng: -12.5, lat: 48.75 }),
getBearing: () => 12,
getPitch: () => null,
}
};
const uh = new URLHandler(v);
expect(uh.currentMapString()).toBe("18/48.75/-12.5/12");
});
it("works with zoom+center+pitch", () => {
const v = {
addEventListener: jest.fn(),
map: {
getZoom: () => 18,
getCenter: () => ({ lng: -12.5, lat: 48.75 }),
getBearing: () => null,
getPitch: () => 65,
},
};
const uh = new URLHandler(v);
expect(uh.currentMapString()).toBe("18/48.75/-12.5/0/65");
});
it("works with zoom+center+bearing+pitch", () => {
const v = {
addEventListener: jest.fn(),
map: {
getZoom: () => 18,
getCenter: () => ({ lng: -12.5, lat: 48.75 }),
getBearing: () => 42,
getPitch: () => 65,
},
};
const uh = new URLHandler(v);
expect(uh.currentMapString()).toBe("18/48.75/-12.5/42/65");
});
});
describe("currentPSVString", () => {
it("works", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getXYZ: () => ({ x: 12, y: 50, z: 75 }),
},
};
const uh = new URLHandler(v);
expect(uh.currentPSVString()).toBe("12.00/50.00/75");
});
it("rounds to 2 decimals", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getXYZ: () => ({ x: 12.123456, y: 50.789456, z: 75 }),
getPictureId: () => null,
},
};
const uh = new URLHandler(v);
expect(uh.currentPSVString()).toBe("12.12/50.79/75");
});
it("works without z", () => {
const v = {
addEventListener: jest.fn(),
psv: {
getXYZ: () => ({ x: 12, y: 50 }),
getPictureId: () => null,
},
};
const uh = new URLHandler(v);
expect(uh.currentPSVString()).toBe("12.00/50.00/0");
});
});
describe("_onParentChange", () => {
it("works", async () => {
delete window.history;
delete window.location;
window.history = { replaceState: jest.fn(), state: {} };
window.location = { href: "http://localhost:5000/?nav=pic&speed=2", search: "?nav=pic&speed=2", hash: "" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
uh.nextURLString = () => "?map=1/2/3";
uh.dispatchEvent = jest.fn();
uh._onParentChange();
await new Promise((r) => setTimeout(r, 1000));
expect(window.history.replaceState.mock.calls.pop()).toEqual([{}, null, "http://localhost:5000/?map=1/2/3"]);
expect(uh.dispatchEvent.mock.calls).toMatchSnapshot();
});
it("works with pic change", async () => {
delete window.history;
delete window.location;
window.history = { pushState: jest.fn(), state: {} };
window.location = { href: "http://localhost:5000/?pic=bla", search: "?pic=bla", hash: "" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
uh.nextURLString = () => "?nav=seq";
uh.dispatchEvent = jest.fn();
uh._onParentChange();
await new Promise((r) => setTimeout(r, 1000));
expect(window.history.pushState.mock.calls.pop()).toEqual([{}, null, "http://localhost:5000/?nav=seq"]);
expect(uh.dispatchEvent.mock.calls).toMatchSnapshot();
});
it("deduplicates calls", async () => {
delete window.history;
delete window.location;
window.history = { replaceState: jest.fn(), state: {} };
window.location = { href: "http://localhost:5000/?speed=1&nav=seq", search: "?speed=1&nav=seq", hash: "" };
const v = { addEventListener: jest.fn() };
const uh = new URLHandler(v);
uh.nextURLString = () => "?map=1/2/3";
for(let i=0; i <= 10; i++) {
uh._onParentChange();
}
await new Promise((r) => setTimeout(r, 1000));
expect(window.history.replaceState.mock.calls).toEqual([[{}, null, "http://localhost:5000/?map=1/2/3"]]);
});
});