From d0b4f7989398a1dca03b65cf0fa3a9f21cfb540d Mon Sep 17 00:00:00 2001 From: Erin Millard Date: Wed, 6 Sep 2023 10:43:45 +1000 Subject: [PATCH] Implement delegated Geolocation --- src/delegated-geolocation.ts | 42 ++++++++++++++++++ src/index.ts | 2 + test/jest/delegated.spec.ts | 84 ++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 src/delegated-geolocation.ts create mode 100644 test/jest/delegated.spec.ts diff --git a/src/delegated-geolocation.ts b/src/delegated-geolocation.ts new file mode 100644 index 0000000..867a60a --- /dev/null +++ b/src/delegated-geolocation.ts @@ -0,0 +1,42 @@ +import { StdGeolocation } from "./types/std.js"; + +let canConstruct = false; + +export function createDelegatedGeolocation(_: { + delegates: StdGeolocation[]; +}): { + geolocation: StdGeolocation; + selectDelegate: SelectDelegate; +} { + canConstruct = true; + + return { + geolocation: new Geolocation(), + + selectDelegate() {}, + }; +} + +export type SelectDelegate = (delegate: StdGeolocation) => void; + +export class Geolocation { + /** + * @deprecated Use the `createDelegatedPermissions()` function instead. + */ + constructor() { + if (!canConstruct) throw new TypeError("Illegal constructor"); + canConstruct = false; + } + + getCurrentPosition(): void { + throw new Error("Not implemented"); + } + + watchPosition(): number { + throw new Error("Not implemented"); + } + + clearWatch(): void { + throw new Error("Not implemented"); + } +} diff --git a/src/index.ts b/src/index.ts index 8f7da63..c7bbaa2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ +export { createDelegatedGeolocation } from "./delegated-geolocation.js"; +export type { SelectDelegate } from "./delegated-geolocation.js"; export { GeolocationCoordinates, createCoordinates, diff --git a/test/jest/delegated.spec.ts b/test/jest/delegated.spec.ts new file mode 100644 index 0000000..66843b1 --- /dev/null +++ b/test/jest/delegated.spec.ts @@ -0,0 +1,84 @@ +import { + Permissions, + createPermissionStore, + createPermissions, +} from "fake-permissions"; +import { GEOLOCATION } from "fake-permissions/constants/permission-name"; +import { PROMPT } from "fake-permissions/constants/permission-state"; +import { + MutableLocationServices, + SelectDelegate, + User, + createDelegatedGeolocation, + createGeolocation, + createLocationServices, + createUser, +} from "../../src/index.js"; +import { StdGeolocation } from "../../src/types/std.js"; + +describe("Delegated geolocation", () => { + let locationServicesA: MutableLocationServices; + let locationServicesB: MutableLocationServices; + let permissionsA: Permissions; + let permissionsB: Permissions; + let userA: User; + let userB: User; + let delegateA: StdGeolocation; + let delegateB: StdGeolocation; + let geolocation: StdGeolocation; + let selectDelegate: SelectDelegate; + + beforeEach(() => { + locationServicesA = createLocationServices(); + locationServicesB = createLocationServices(); + + const permissionStoreA = createPermissionStore({ + initialStates: new Map([[{ name: GEOLOCATION }, PROMPT]]), + }); + const permissionStoreB = createPermissionStore({ + initialStates: new Map([[{ name: GEOLOCATION }, PROMPT]]), + }); + + permissionsA = createPermissions({ permissionStore: permissionStoreA }); + permissionsB = createPermissions({ permissionStore: permissionStoreB }); + + userA = createUser({ + locationServices: locationServicesA, + permissionStore: permissionStoreA, + }); + userB = createUser({ + locationServices: locationServicesB, + permissionStore: permissionStoreB, + }); + + delegateA = createGeolocation({ + async requestPermission(descriptor) { + return userA.requestPermission(descriptor); + }, + + locationServices: locationServicesA, + permissions: permissionsA, + }); + delegateB = createGeolocation({ + async requestPermission(descriptor) { + return userB.requestPermission(descriptor); + }, + + locationServices: locationServicesB, + permissions: permissionsB, + }); + + ({ geolocation, selectDelegate } = createDelegatedGeolocation({ + delegates: [delegateA, delegateB], + })); + }); + + it("cannot be instantiated directly", async () => { + const instantiateGeolocation = () => { + new (geolocation.constructor as new (p: object) => unknown)({}); + }; + + expect(instantiateGeolocation).toThrow(TypeError); + expect(instantiateGeolocation).toThrow("Illegal constructor"); + }); +});