added web account context test

This commit is contained in:
balzack 2023-01-12 06:01:32 -08:00
parent e068273487
commit 132d7cc003
6 changed files with 164 additions and 31 deletions

View File

@ -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 }

View File

@ -38,10 +38,19 @@ export function useAppContext(websocket) {
const cardContext = useContext(CardContext);
const setSession = (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);
}

View File

@ -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 (
<div>
<span data-testid="count">{ renderCount }</span>
<span data-testid="seal">{ account.state.seal }</span>
<span data-testid="sealKey">{ account.state.sealKey }</span>
<span data-testid="searchable">{ account.state.status?.searchable.toString() }</span>
</div>
);
}
function AccountTestApp() {
return (
<StoreContextProvider>
<AccountContextProvider>
<AccountView />
</AccountContextProvider>
</StoreContextProvider>
)
}
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(<AccountTestApp />);
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');
});
});

View File

@ -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));
});

View File

@ -96,8 +96,6 @@ beforeEach(() => {
});
}
else {
console.log(params, options);
return Promise.resolve({
url: 'endpoint',
status: 200,

View File

@ -131,7 +131,6 @@ beforeEach(() => {
});
}
else {
console.log(params, options);
return Promise.resolve({
url: 'endpoint',
status: 200,