diff --git a/net/web/src/context/useAppContext.hook.js b/net/web/src/context/useAppContext.hook.js index ac9e7d76..b7884948 100644 --- a/net/web/src/context/useAppContext.hook.js +++ b/net/web/src/context/useAppContext.hook.js @@ -15,7 +15,7 @@ import { createWebsocket } from 'api/fetchUtil'; export function useAppContext(websocket) { const [state, setState] = useState({ - disconnected: true, + status: 'disconnected', }); const [appRevision, setAppRevision] = useState(); @@ -23,8 +23,8 @@ export function useAppContext(websocket) { const appVersion = "1.0.0"; const userAgent = window.navigator.userAgent; + const access = useRef(null); const ws = useRef(null); - const revision = useRef(null); const updateState = (value) => { setState((s) => ({ ...s, ...value })) @@ -37,21 +37,28 @@ export function useAppContext(websocket) { const channelContext = useContext(ChannelContext); const cardContext = useContext(CardContext); - const resetData = () => { - revision.current = null; + const setSession = (token) => { + accountContext.actions.setToken(token); + profileContext.actions.setToken(token); + cardContext.actions.setToken(token); + channelContext.actions.setToken(token); + setWebsocket(token); + } + + const clearSession = () => { + uploadContext.actions.clear(); + storeContext.actions.clear(); + accountContext.actions.clearToken(); profileContext.actions.clearToken(); cardContext.actions.clearToken(); channelContext.actions.clearToken(); - setState({}); + clearWebsocket(); } const actions = { - logout: () => { - appLogout(); - storeContext.actions.clear(); - uploadContext.actions.clear(); - resetData(); + logout: async () => { + await appLogout(); }, access: async (token) => { await appAccess(token) @@ -62,21 +69,14 @@ export function useAppContext(websocket) { create: async (username, password, token) => { await appCreate(username, password, token) }, - username: getUsername, - available: getAvailable, } const appCreate = async (username, password, token) => { await addAccount(username, password, token); - let access = await setLogin(username, password, appName, appVersion, userAgent) - updateState({ access: access.appToken }); + const access = await setLogin(username, password, appName, appVersion, userAgent); storeContext.actions.setValue('login:timestamp', access.created); - accountContext.actions.setToken(access.appToken); - profileContext.actions.setToken(access.appToken); - cardContext.actions.setToken(access.appToken); - channelContext.actions.setToken(access.appToken); + setSession(access.appToken); - setWebsocket(access.appToken) localStorage.setItem("session", JSON.stringify({ access: access.appToken, timestamp: access.created, @@ -85,15 +85,10 @@ export function useAppContext(websocket) { } const appLogin = async (username, password) => { - let access = await setLogin(username, password, appName, appVersion, userAgent) - updateState({ access: access.appToken }); + const access = await setLogin(username, password, appName, appVersion, userAgent); storeContext.actions.setValue('login:timestamp', access.created); - accountContext.actions.setToken(access.appToken); - profileContext.actions.setToken(access.appToken); - cardContext.actions.setToken(access.appToken); - channelContext.actions.setToken(access.appToken); + setSession(access.appToken); - setWebsocket(access.appToken) localStorage.setItem("session", JSON.stringify({ access: access.appToken, timestamp: access.created, @@ -102,15 +97,10 @@ export function useAppContext(websocket) { } const appAccess = async (token) => { - let access = await setAccountAccess(token, appName, appVersion, userAgent) - updateState({ access: access.appToken }); + const access = await setAccountAccess(token, appName, appVersion, userAgent); storeContext.actions.setValue('login:timestamp', access.created); - accountContext.actions.setToken(access.appToken); - profileContext.actions.setToken(access.appToken); - cardContext.actions.setToken(access.appToken); - channelContext.actions.setToken(access.appToken); + setSession(access.appToken); - setWebsocket(access.appToken) localStorage.setItem("session", JSON.stringify({ access: access.appToken, timestamp: access.created, @@ -119,21 +109,15 @@ export function useAppContext(websocket) { } const appLogout = async () => { + clearSession(); try { - await clearLogin(state.access); + await clearLogin(access.current); } catch (err) { console.log(err); } - updateState({ access: null }); - accountContext.actions.clearToken(); - profileContext.actions.clearToken(); - cardContext.actions.clearToken(); - channelContext.actions.clearToken(); - - clearWebsocket() localStorage.removeItem("session"); - } + }; useEffect(() => { if (appRevision) { @@ -154,20 +138,22 @@ export function useAppContext(websocket) { protocol = 'wss://'; } + updateState({ status: 'connecting' }); ws.current = createWebsocket(protocol + window.location.host + "/status"); ws.current.onmessage = (ev) => { try { let rev = JSON.parse(ev.data); + updateState({ status: 'connected' }); setAppRevision(rev); - updateState({ disconnected: false }); } catch (err) { console.log(err); + ws.current.close(); } } ws.current.onclose = (e) => { - updateState({ disconnected: true }); console.log(e) + updateState({ status: 'disconnected' }); setTimeout(() => { if (ws.current != null) { ws.current.onmessage = () => {} @@ -176,14 +162,15 @@ export function useAppContext(websocket) { ws.current.onerror = () => {} setWebsocket(token); } - }, 1000) + }, 1000); } ws.current.onopen = () => { ws.current.send(JSON.stringify({ AppToken: token })) } ws.current.error = (e) => { - updateState({ disconnected: true }); console.log(e) + ws.current.close(); + updateState({ status: 'disconnected' }); } } @@ -191,6 +178,7 @@ export function useAppContext(websocket) { ws.current.onclose = () => {} ws.current.close() ws.current = null + updateState({ status: 'disconnected' }); } useEffect(() => { @@ -199,25 +187,16 @@ export function useAppContext(websocket) { try { const session = JSON.parse(storage) if (session?.access) { - setState({ access: session.access }) - setWebsocket(session.access); - } else { - setState({}) + setSession(session.access); } } catch(err) { console.log(err) - setState({}) } - } else { - setState({}) } // eslint-disable-next-line }, []); - if (state == null) { - return {}; - } return { state, actions } } diff --git a/net/web/test/App.test.js b/net/web/test/App.test.js index 5b2c2773..211e49f1 100644 --- a/net/web/test/App.test.js +++ b/net/web/test/App.test.js @@ -12,10 +12,9 @@ import { UploadContextProvider } from 'context/UploadContext'; import { ViewportContextProvider } from 'context/ViewportContext'; import { ConversationContextProvider } from 'context/ConversationContext'; +let mockWebsocket; function MockWebsocket(url) { - setTimeout(() => { - this.onmessage({ data: JSON.stringify({ account: 1, profile: 1, card: 1, channel: 1 }) }); - }); + this.url = url; }; let appContext = null; @@ -31,7 +30,7 @@ function AppView() { return (
{ renderCount } - { app.state.disconnected ? 'true' : 'false' } + { app.state.status }
); } @@ -64,7 +63,8 @@ const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout; beforeEach(() => { const mockCreateWebsocket = jest.fn().mockImplementation((url) => { - return new MockWebsocket(url); + mockWebsocket = new MockWebsocket(url); + return mockWebsocket; }); const mockFetch = jest.fn().mockImplementation((url, options) => { @@ -102,10 +102,29 @@ test('testing app sync', async () => { await act(async () => { appContext.actions.login('testlogin', 'testpassword'); + expect(mockWebsocket?.onmessage).not.toBe(null); + expect(mockWebsocket?.onclose).not.toBe(null); }); await waitFor(async () => { - expect(screen.getByTestId('disconnected').textContent).toBe('false'); + expect(screen.getByTestId('status').textContent).toBe('connecting'); + }); + + await act(async () => { + mockWebsocket.onmessage({ data: JSON.stringify({ account: 1, profile: 1, card: 1, channel: 1 }) }); + }); + + await waitFor(async () => { + expect(screen.getByTestId('status').textContent).toBe('connected'); + }); + + await act(async () => { + mockWebsocket.onclose(); + await new Promise(r => setTimeout(r, 1000)); + }); + + await waitFor(async () => { + expect(screen.getByTestId('status').textContent).toBe('connecting'); }); });