diff --git a/libs/permissions/permissionLogic/src/lib/permission-logic.spec.ts b/libs/permissions/permissionLogic/src/lib/permission-logic.spec.ts index 9030f08..95bb08a 100644 --- a/libs/permissions/permissionLogic/src/lib/permission-logic.spec.ts +++ b/libs/permissions/permissionLogic/src/lib/permission-logic.spec.ts @@ -29,19 +29,130 @@ import { permissionMonitoringMachine, } from './permissionMonitor.machine'; +const permissionReportingMachine = setup({ + types: { + input: {} as { + permissions: Array; + parent: AnyActorRef; + }, + context: {} as { + permissions: Array; + parent: AnyActorRef; + }, + }, + actions: { + sendSubscriptionRequestForStatusUpdates: sendTo( + ({ system }) => { + const actorRef: AnyActorRef = system.get( + ActorSystemIds.permissionMonitoring + ); + return actorRef; + }, + ({ self, context }) => ({ + type: 'subscribeToPermissionStatuses', + permissions: context.permissions, + self, + }) + ), + // satisfies /*TODO type these events to the receiving machine event type*/ AnyEventObject); + checkedSendParent: enqueueActions( + ({ context, enqueue }, event: AnyEventObject) => { + if (!context.parent) { + console.log( + 'WARN: an attempt to send an event to a non-existent parent' + ); + return; + } + + enqueue.sendTo(context.parent, event); + } + ), + }, +}).createMachine({ + description: + "This actor's job is to report permission statuses to the actors that have invoked it. We abstract away this functionality so that it is reusable by any actor that needs it and so they don't need to know how permissions are checked. This keeps control centralized and easy to modify the behavior of.", + context: ({ input }) => ({ + permissions: input.permissions, + parent: input.parent, + }), + entry: [ + 'sendSubscriptionRequestForStatusUpdates', + log('subscribe to status updates'), + ], + on: { + requestPermission: { + actions: [ + sendTo( + ({ system }) => { + return system.get(ActorSystemIds.permissionCheckerAndRequester); + }, + ({ event }) => ({ + type: 'triggerPermissionRequest', + permission: event.permission, + }) + ), + ], + }, + permissionStatusChanged: { + description: + 'Whenever the Permission Monitoring machine reports that a permission status has changed, we receive this event and can process and share with our siblings.', + // We eventually want to communicate this to the actors that have invoked us + actions: [ + log( + ({ event }) => + event.permission + ' status << { + return { + type: 'requestPermission', + // @ts-expect-error TODO make this type safe + permission: event.permission, + }; + }), + ], + }, + }, + invoke: { + id: 'permissionHandler', + src: 'permissionReportingMachine', + input: ({ self }) => ({ + permissions: [Permissions.bluetooth], + parent: self, + }), }, }, }, @@ -118,13 +239,13 @@ describe('Counting Machine That Needs Permission At 3', () => { expect(countingActor.getSnapshot().context.count).toBe(3); expect(countingActor.getSnapshot().value).toStrictEqual({ counting: 'enabled', - handlingPermissions: 'idle', + handlingPermissions: {}, }); countingActor.send({ type: 'count.inc' }); expect(countingActor.getSnapshot().value).toStrictEqual({ counting: 'disabled', - handlingPermissions: 'active', + handlingPermissions: {}, }); expect(countingActor.getSnapshot().context.count).toBe(3); @@ -140,7 +261,7 @@ describe('Counting Machine That Needs Permission At 3', () => { ).start(); expect(countingActor.getSnapshot().value).toStrictEqual({ counting: 'enabled', - handlingPermissions: 'idle', + handlingPermissions: {}, }); }); @@ -345,134 +466,15 @@ describe('Permission Monitoring Machine', () => { ); }); - const permissionReportingMachine = setup({ - types: { - input: {} as { - permissions: Array; - parent: AnyActorRef; - }, - context: {} as { - permissions: Array; - parent: AnyActorRef; - }, - }, - actions: { - sendSubscriptionRequestForStatusUpdates: sendTo( - ({ system }) => { - const actorRef: AnyActorRef = system.get( - ActorSystemIds.permissionMonitoring - ); - return actorRef; - }, - ({ self, context }) => ({ - type: 'subscribeToPermissionStatuses', - permissions: context.permissions, - self, - }) - ), - // satisfies /*TODO type these events to the receiving machine event type*/ AnyEventObject); - checkedSendParent: enqueueActions( - ({ context, enqueue }, event: AnyEventObject) => { - if (!context.parent) { - console.log( - 'WARN: an attempt to send an event to a non-existent parent' - ); - return; - } - - enqueue.sendTo(context.parent, event); - } - ), - }, - }).createMachine({ - description: - "This actor's job is to report permission statuses to the actors that have invoked it. We abstract away this functionality so that it is reusable by any actor that needs it and so they don't need to know how permissions are checked. This keeps control centralized and easy to modify the behavior of.", - id: ActorSystemIds.permissionReporting, - context: ({ input }) => ({ - permissions: input.permissions, - parent: input.parent, - }), - entry: [ - 'sendSubscriptionRequestForStatusUpdates', - log('subscribe to status updates'), - ], - on: { - requestPermission: { - actions: [ - sendTo( - ({ system }) => { - return system.get(ActorSystemIds.permissionCheckerAndRequester); - }, - ({ event }) => ({ - type: 'triggerPermissionRequest', - permission: event.permission, - }) - ), - ], - }, - permissionStatusChanged: { - description: - 'Whenever the Permission Monitoring machine reports that a permission status has changed, we receive this event and can process and share with our siblings.', - // We eventually want to communicate this to the actors that have invoked us - actions: [ - log( - ({ event }) => - event.permission + ' status << { - console.log('logging::::' + JSON.stringify(event, null, 2)); - }, - ], - }, - }, - }, foo: { initial: 'start', states: { @@ -553,7 +555,7 @@ describe('Permission Monitoring Machine', () => { const id = state.context.permissionSubscribers[Permissions.bluetooth][0].id; - console.log({ id }); + expect(id).toBe('permissionHandler'); }); it('should notify subscribers of changes to permissions', async () => { @@ -582,7 +584,6 @@ describe('Permission Monitoring Machine', () => { expect(featureMachineActor?.getSnapshot().value).toStrictEqual({ foo: 'waitingForPermission', handlingPermissions: {}, - logging: {}, }); expect(permissionMonitorActor.getSnapshot().value).toStrictEqual({ @@ -599,7 +600,7 @@ describe('Permission Monitoring Machine', () => { const permissionCheckerActor = permissionMonitorActor.getSnapshot().children[ ActorSystemIds.permissionCheckerAndRequester - ]; + ]!; expect(permissionCheckerActor?.getSnapshot().value).toBe( 'checkingPermissions' @@ -618,7 +619,6 @@ describe('Permission Monitoring Machine', () => { expect(featureMachineActor?.getSnapshot().value).toStrictEqual({ foo: 'bluetoothDenied', handlingPermissions: {}, - logging: {}, }); // await waitFor(featureMachineActor, (state) => { @@ -640,7 +640,6 @@ describe('Permission Monitoring Machine', () => { expect(featureMachineActor?.getSnapshot().value).toStrictEqual({ foo: 'bluetoothGranted', handlingPermissions: {}, - logging: {}, }); // await new Promise((resolve) => setTimeout(resolve, forever)); }); @@ -763,6 +762,6 @@ describe('Permission Monitoring Machine', () => { it('should immediately report back to parent if permission is already granted', async () => {}); describe('Blocked Permission', () => { - it('should immediately report back to parent if permission is already granted', async () => {}); + it('should immediately report back to parent if permission is blocked', async () => {}); }); }); diff --git a/libs/permissions/permissionLogic/src/lib/permissionMonitor.machine.ts b/libs/permissions/permissionLogic/src/lib/permissionMonitor.machine.ts index a232467..68c2041 100644 --- a/libs/permissions/permissionLogic/src/lib/permissionMonitor.machine.ts +++ b/libs/permissions/permissionLogic/src/lib/permissionMonitor.machine.ts @@ -104,6 +104,7 @@ export const permissionMonitoringMachine = setup({ type: 'parallel', // TODO: this should live at the top level of the application, not here + // https://jabraenhance.atlassian.net/browse/JES-3817 invoke: [ { src: 'features',