about summary refs log tree commit diff
path: root/src/components/PolicyUpdateOverlay/__tests__/useAnnouncementState.test.ts
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2025-08-06 15:15:52 -0500
committerGitHub <noreply@github.com>2025-08-06 15:15:52 -0500
commit328aa2be9482f77cb1cf86c5d227fdcee9981b16 (patch)
tree27174f10e0fe80288c0cd6907f8686486131d082 /src/components/PolicyUpdateOverlay/__tests__/useAnnouncementState.test.ts
parentfd37d92f85ddf0f075a67c4e9b2d85bef38f1835 (diff)
downloadvoidsky-328aa2be9482f77cb1cf86c5d227fdcee9981b16.tar.zst
[APP-1356] Policy update dialog (#8782)
* Add blocking announcement dialog feature

* WIP custom dialog

* Rework dialog and add native FocusScope

* Lock scroll on web, fix backdrop

* Add web FocusScope

* Create custom Outlet for these announcements

* Clean up FocusScope native impl

* Comments

* Some styling fixes

* Handle screen reader specifically

* Clean up state, remove Portal edits

* Reorg, rename

* Add syncing, tests

* Revert dialog updates

* Revert formatting

* Delete unused file

* Format

* Add FullWindowOverlay

* remove mmkv storage in debug btn

* Add debug code

* fix taps passing through on iOS

* Reorg

* Reorg, rename everything

* Complete policy update after signup

* Add logger

* Move context around, unmount portals on native

* Move a11y prop into FocusScope

* Remove useMemo

* Update dates

* Move debug to dev settings

* Unmount web portals until policy update completed

* UPdate dates

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Diffstat (limited to 'src/components/PolicyUpdateOverlay/__tests__/useAnnouncementState.test.ts')
-rw-r--r--src/components/PolicyUpdateOverlay/__tests__/useAnnouncementState.test.ts195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/components/PolicyUpdateOverlay/__tests__/useAnnouncementState.test.ts b/src/components/PolicyUpdateOverlay/__tests__/useAnnouncementState.test.ts
new file mode 100644
index 000000000..f6055bf34
--- /dev/null
+++ b/src/components/PolicyUpdateOverlay/__tests__/useAnnouncementState.test.ts
@@ -0,0 +1,195 @@
+import {describe, test} from '@jest/globals'
+
+import {
+  computeCompletedState,
+  syncCompletedState,
+} from '#/components/PolicyUpdateOverlay/usePolicyUpdateState'
+
+jest.mock('../../../state/queries/nuxs')
+
+describe('computeCompletedState', () => {
+  test(`initial state`, () => {
+    const completed = computeCompletedState({
+      nuxIsReady: false,
+      nuxIsCompleted: false,
+      nuxIsOptimisticallyCompleted: false,
+      completedForDevice: undefined,
+    })
+
+    expect(completed).toBe(true)
+  })
+
+  test(`nux loaded state`, () => {
+    const completed = computeCompletedState({
+      nuxIsReady: true,
+      nuxIsCompleted: false,
+      nuxIsOptimisticallyCompleted: false,
+      completedForDevice: undefined,
+    })
+
+    expect(completed).toBe(false)
+  })
+
+  test(`nux saving state`, () => {
+    const completed = computeCompletedState({
+      nuxIsReady: true,
+      nuxIsCompleted: false,
+      nuxIsOptimisticallyCompleted: true,
+      completedForDevice: undefined,
+    })
+
+    expect(completed).toBe(true)
+  })
+
+  test(`nux is completed`, () => {
+    const completed = computeCompletedState({
+      nuxIsReady: true,
+      nuxIsCompleted: true,
+      nuxIsOptimisticallyCompleted: false,
+      completedForDevice: undefined,
+    })
+
+    expect(completed).toBe(true)
+  })
+
+  test(`initial state, but already completed for device`, () => {
+    const completed = computeCompletedState({
+      nuxIsReady: false,
+      nuxIsCompleted: false,
+      nuxIsOptimisticallyCompleted: false,
+      completedForDevice: true,
+    })
+
+    expect(completed).toBe(true)
+  })
+})
+
+describe('syncCompletedState', () => {
+  describe('!nuxIsReady', () => {
+    test(`!completedForDevice, no-op`, () => {
+      const save = jest.fn()
+      const setCompletedForDevice = jest.fn()
+      syncCompletedState({
+        nuxIsReady: false,
+        nuxIsCompleted: false,
+        nuxIsOptimisticallyCompleted: false,
+        completedForDevice: false,
+        save,
+        setCompletedForDevice,
+      })
+
+      expect(save).not.toHaveBeenCalled()
+      expect(setCompletedForDevice).not.toHaveBeenCalled()
+    })
+
+    test(`completedForDevice, no-op`, () => {
+      const save = jest.fn()
+      const setCompletedForDevice = jest.fn()
+      syncCompletedState({
+        nuxIsReady: false,
+        nuxIsCompleted: false,
+        nuxIsOptimisticallyCompleted: false,
+        completedForDevice: true,
+        save,
+        setCompletedForDevice,
+      })
+
+      expect(save).not.toHaveBeenCalled()
+      expect(setCompletedForDevice).not.toHaveBeenCalled()
+    })
+  })
+
+  describe('nuxIsReady', () => {
+    describe(`!nuxIsCompleted`, () => {
+      describe(`!nuxIsOptimisticallyCompleted`, () => {
+        test(`!completedForDevice, no-op`, () => {
+          const save = jest.fn()
+          const setCompletedForDevice = jest.fn()
+          syncCompletedState({
+            nuxIsReady: true,
+            nuxIsCompleted: false,
+            nuxIsOptimisticallyCompleted: false,
+            completedForDevice: false,
+            save,
+            setCompletedForDevice,
+          })
+
+          expect(save).not.toHaveBeenCalled()
+          expect(setCompletedForDevice).not.toHaveBeenCalled()
+        })
+
+        test(`completedForDevice, syncs to server`, () => {
+          const save = jest.fn()
+          const setCompletedForDevice = jest.fn()
+          syncCompletedState({
+            nuxIsReady: true,
+            nuxIsCompleted: false,
+            nuxIsOptimisticallyCompleted: false,
+            completedForDevice: true,
+            save,
+            setCompletedForDevice,
+          })
+
+          expect(save).toHaveBeenCalled()
+          expect(setCompletedForDevice).not.toHaveBeenCalled()
+        })
+      })
+
+      /**
+       * Catches the case where we already called `save` to sync device state
+       * to server, thus `nuxIsOptimisticallyCompleted` is true.
+       */
+      describe(`nuxIsOptimisticallyCompleted`, () => {
+        test(`completedForDevice, no-op`, () => {
+          const save = jest.fn()
+          const setCompletedForDevice = jest.fn()
+          syncCompletedState({
+            nuxIsReady: true,
+            nuxIsCompleted: false,
+            nuxIsOptimisticallyCompleted: true,
+            completedForDevice: true,
+            save,
+            setCompletedForDevice,
+          })
+
+          expect(save).not.toHaveBeenCalled()
+          expect(setCompletedForDevice).not.toHaveBeenCalled()
+        })
+      })
+    })
+
+    describe(`nuxIsCompleted`, () => {
+      test(`!completedForDevice, syncs to device`, () => {
+        const save = jest.fn()
+        const setCompletedForDevice = jest.fn()
+        syncCompletedState({
+          nuxIsReady: true,
+          nuxIsCompleted: true,
+          nuxIsOptimisticallyCompleted: false,
+          completedForDevice: false,
+          save,
+          setCompletedForDevice,
+        })
+
+        expect(save).not.toHaveBeenCalled()
+        expect(setCompletedForDevice).toHaveBeenCalled()
+      })
+
+      test(`completedForDevice, no-op`, () => {
+        const save = jest.fn()
+        const setCompletedForDevice = jest.fn()
+        syncCompletedState({
+          nuxIsReady: true,
+          nuxIsCompleted: true,
+          nuxIsOptimisticallyCompleted: false,
+          completedForDevice: true,
+          save,
+          setCompletedForDevice,
+        })
+
+        expect(save).not.toHaveBeenCalled()
+        expect(setCompletedForDevice).not.toHaveBeenCalled()
+      })
+    })
+  })
+})