From 132d7cc003e566687555b62699255fd4b437c926 Mon Sep 17 00:00:00 2001 From: balzack Date: Thu, 12 Jan 2023 06:01:32 -0800 Subject: [PATCH] added web account context test --- net/web/src/context/useAccountContext.hook.js | 59 +++++---- net/web/src/context/useAppContext.hook.js | 17 ++- net/web/test/Account.test.js | 112 ++++++++++++++++++ net/web/test/App.test.js | 4 +- net/web/test/Card.test.js | 2 - net/web/test/Conversation.test.js | 1 - 6 files changed, 164 insertions(+), 31 deletions(-) create mode 100644 net/web/test/Account.test.js diff --git a/net/web/src/context/useAccountContext.hook.js b/net/web/src/context/useAccountContext.hook.js index 6f6f999f..f4777858 100644 --- a/net/web/src/context/useAccountContext.hook.js +++ b/net/web/src/context/useAccountContext.hook.js @@ -7,14 +7,16 @@ import { StoreContext } from './StoreContext'; export function useAccountContext() { const [state, setState] = useState({ - init: false, + offsync: false, status: null, seal: null, - sealPrivate: null, + sealKey: null, }); const access = useRef(null); - const revision = useRef(null); - const next = useRef(null); + const setRevision = useRef(null); + const curRevision = useRef(null); + const syncing = useRef(false); + const force = useRef(false); const storeContext = useContext(StoreContext); @@ -24,37 +26,48 @@ export function useAccountContext() { useEffect(() => { updateState({ sealKey: storeContext.state.sealKey }); - }, [storeContext.state.sealKey]); + }, [storeContext.state]); - const setStatus = async (rev) => { - if (next.current == null) { - if (revision.current !== rev) { - let status = await getAccountStatus(access.current); - updateState({ init: true, status, seal: status.seal }); - revision.current = rev; + const sync = async () => { + if (!syncing.current && (setRevision.current !== curRevision.current || force.current)) { + syncing.current = true; + force.current = false; + + try { + const token = access.current; + const revision = curRevision.current; + const status = await getAccountStatus(token); + setRevision.current = revision; + updateState({ offsync: false, status, seal: status.seal }); } - if (next.current != null) { - let r = next.current; - next.current = null; - setStatus(r); + catch (err) { + console.log(err); + syncing.current = false; + updateState({ offsync: true }); + return; } - } - else { - next.current = rev; + + syncing.current = false; + await sync(); } } const actions = { setToken: (token) => { + if (access.current || syncing.current) { + throw new Error("invalid account session state"); + } access.current = token; + curRevision.current = null; + setRevision.current = null; + setState({ offsync: false, status: null, seal: null, sealKey: null }); }, clearToken: () => { access.current = null; - revision.current = 0; - setState({ init: false, seal: {}, sealKey: {} }); }, setRevision: async (rev) => { - setStatus(rev); + curRevision.current = rev; + await sync(); }, setSearchable: async (flag) => { await setAccountSearchable(access.current, flag); @@ -74,6 +87,10 @@ export function useAccountContext() { setLogin: async (username, password) => { await setAccountLogin(access.current, username, password); }, + resync: async () => { + force.current = true; + await sync(); + }, } return { state, actions } diff --git a/net/web/src/context/useAppContext.hook.js b/net/web/src/context/useAppContext.hook.js index b7884948..7d317612 100644 --- a/net/web/src/context/useAppContext.hook.js +++ b/net/web/src/context/useAppContext.hook.js @@ -38,10 +38,19 @@ export function useAppContext(websocket) { const cardContext = useContext(CardContext); const setSession = (token) => { - accountContext.actions.setToken(token); - profileContext.actions.setToken(token); - cardContext.actions.setToken(token); - channelContext.actions.setToken(token); + try { + accountContext.actions.setToken(token); + profileContext.actions.setToken(token); + cardContext.actions.setToken(token); + channelContext.actions.setToken(token); + } + catch (err) { + accountContext.actions.clearToken(); + profileContext.actions.clearToken(); + cardContext.actions.clearToken(); + channelContext.actions.clearToken(); + throw err; + } setWebsocket(token); } diff --git a/net/web/test/Account.test.js b/net/web/test/Account.test.js new file mode 100644 index 00000000..d0860cb9 --- /dev/null +++ b/net/web/test/Account.test.js @@ -0,0 +1,112 @@ +import React, { useState, useEffect, useContext } from 'react'; +import {render, act, screen, waitFor, fireEvent} from '@testing-library/react' +import { AccountContextProvider, AccountContext } from 'context/AccountContext'; +import { StoreContextProvider } from 'context/StoreContext'; +import * as fetchUtil from 'api/fetchUtil'; + +let accountContext = null; +function AccountView() { + const [renderCount, setRenderCount] = useState(0); + const account = useContext(AccountContext); + accountContext = account; + + useEffect(() => { + setRenderCount(renderCount + 1); + }, [account.state]); + + return ( +
+ { renderCount } + { account.state.seal } + { account.state.sealKey } + { account.state.status?.searchable.toString() } +
+ ); +} + +function AccountTestApp() { + return ( + + + + + + ) +} + +const realFetchWithTimeout = fetchUtil.fetchWithTimeout; +const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout; +let fetchStatus; +let sealSet; + +beforeEach(() => { + fetchStatus = {}; + sealSet = false; + + const mockFetch = jest.fn().mockImplementation((url, options) => { + if (url === '/account/seal?agent=abc123') { + sealSet = true; + return Promise.resolve({ + json: () => Promise.resolve({}) + }); + } + else if (url === '/account/status?agent=abc123') { + return Promise.resolve({ + json: () => Promise.resolve(fetchStatus) + }); + } + else { + return Promise.resolve({ + json: () => Promise.resolve({}) + }); + } + }); + fetchUtil.fetchWithTimeout = mockFetch; + fetchUtil.fetchWithCustomTimeout = mockFetch; +}); + +afterEach(() => { + fetchUtil.fetchWithTimeout = realFetchWithTimeout; + fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout; +}); + +test('testing account sync', async () => { + render(); + + await waitFor(async () => { + expect(accountContext).not.toBe(null); + }); + + fetchStatus = { disabled: false, storageUsed: 1, searchable: true, pushEnabled: false, sealable: true }; + + await act(async () => { + accountContext.actions.setToken('abc123'); + await accountContext.actions.setRevision(1); + }); + + await waitFor(async () => { + expect(screen.getByTestId('searchable').textContent).toBe('true'); + expect(screen.getByTestId('seal').textContent).toBe(''); + expect(screen.getByTestId('sealKey').textContent).toBe(''); + expect(sealSet).toBe(false); + }); + + await act(async () => { + await accountContext.actions.setSeal('testeal', 'testsealkey'); + }); + + fetchStatus = { disabled: false, storageUsed: 1, searchable: true, pushEnabled: false, sealable: true, seal: 'testseal' }; + + await act(async () => { + await accountContext.actions.setRevision(2); + }); + + await waitFor(async () => { + expect(sealSet).toBe(true); + expect(screen.getByTestId('seal').textContent).toBe('testseal'); + expect(screen.getByTestId('sealKey').textContent).toBe('testsealkey'); + }); +}); + + + diff --git a/net/web/test/App.test.js b/net/web/test/App.test.js index 211e49f1..606afe04 100644 --- a/net/web/test/App.test.js +++ b/net/web/test/App.test.js @@ -68,8 +68,6 @@ beforeEach(() => { }); const mockFetch = jest.fn().mockImplementation((url, options) => { - - console.log(url, options); const params = url.split('/'); if (params[1] === 'account' && options.method === 'POST') { return Promise.resolve({ @@ -119,7 +117,7 @@ test('testing app sync', async () => { }); await act(async () => { - mockWebsocket.onclose(); + mockWebsocket.onclose('test close'); await new Promise(r => setTimeout(r, 1000)); }); diff --git a/net/web/test/Card.test.js b/net/web/test/Card.test.js index 1dff7185..42631057 100644 --- a/net/web/test/Card.test.js +++ b/net/web/test/Card.test.js @@ -96,8 +96,6 @@ beforeEach(() => { }); } else { - console.log(params, options); - return Promise.resolve({ url: 'endpoint', status: 200, diff --git a/net/web/test/Conversation.test.js b/net/web/test/Conversation.test.js index bd8f82bc..342af15c 100644 --- a/net/web/test/Conversation.test.js +++ b/net/web/test/Conversation.test.js @@ -131,7 +131,6 @@ beforeEach(() => { }); } else { - console.log(params, options); return Promise.resolve({ url: 'endpoint', status: 200,