mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
added web account context test
This commit is contained in:
parent
e068273487
commit
132d7cc003
@ -7,14 +7,16 @@ import { StoreContext } from './StoreContext';
|
|||||||
|
|
||||||
export function useAccountContext() {
|
export function useAccountContext() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
init: false,
|
offsync: false,
|
||||||
status: null,
|
status: null,
|
||||||
seal: null,
|
seal: null,
|
||||||
sealPrivate: null,
|
sealKey: null,
|
||||||
});
|
});
|
||||||
const access = useRef(null);
|
const access = useRef(null);
|
||||||
const revision = useRef(null);
|
const setRevision = useRef(null);
|
||||||
const next = useRef(null);
|
const curRevision = useRef(null);
|
||||||
|
const syncing = useRef(false);
|
||||||
|
const force = useRef(false);
|
||||||
|
|
||||||
const storeContext = useContext(StoreContext);
|
const storeContext = useContext(StoreContext);
|
||||||
|
|
||||||
@ -24,37 +26,48 @@ export function useAccountContext() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateState({ sealKey: storeContext.state.sealKey });
|
updateState({ sealKey: storeContext.state.sealKey });
|
||||||
}, [storeContext.state.sealKey]);
|
}, [storeContext.state]);
|
||||||
|
|
||||||
const setStatus = async (rev) => {
|
const sync = async () => {
|
||||||
if (next.current == null) {
|
if (!syncing.current && (setRevision.current !== curRevision.current || force.current)) {
|
||||||
if (revision.current !== rev) {
|
syncing.current = true;
|
||||||
let status = await getAccountStatus(access.current);
|
force.current = false;
|
||||||
updateState({ init: true, status, seal: status.seal });
|
|
||||||
revision.current = rev;
|
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) {
|
catch (err) {
|
||||||
let r = next.current;
|
console.log(err);
|
||||||
next.current = null;
|
syncing.current = false;
|
||||||
setStatus(r);
|
updateState({ offsync: true });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
syncing.current = false;
|
||||||
next.current = rev;
|
await sync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setToken: (token) => {
|
setToken: (token) => {
|
||||||
|
if (access.current || syncing.current) {
|
||||||
|
throw new Error("invalid account session state");
|
||||||
|
}
|
||||||
access.current = token;
|
access.current = token;
|
||||||
|
curRevision.current = null;
|
||||||
|
setRevision.current = null;
|
||||||
|
setState({ offsync: false, status: null, seal: null, sealKey: null });
|
||||||
},
|
},
|
||||||
clearToken: () => {
|
clearToken: () => {
|
||||||
access.current = null;
|
access.current = null;
|
||||||
revision.current = 0;
|
|
||||||
setState({ init: false, seal: {}, sealKey: {} });
|
|
||||||
},
|
},
|
||||||
setRevision: async (rev) => {
|
setRevision: async (rev) => {
|
||||||
setStatus(rev);
|
curRevision.current = rev;
|
||||||
|
await sync();
|
||||||
},
|
},
|
||||||
setSearchable: async (flag) => {
|
setSearchable: async (flag) => {
|
||||||
await setAccountSearchable(access.current, flag);
|
await setAccountSearchable(access.current, flag);
|
||||||
@ -74,6 +87,10 @@ export function useAccountContext() {
|
|||||||
setLogin: async (username, password) => {
|
setLogin: async (username, password) => {
|
||||||
await setAccountLogin(access.current, username, password);
|
await setAccountLogin(access.current, username, password);
|
||||||
},
|
},
|
||||||
|
resync: async () => {
|
||||||
|
force.current = true;
|
||||||
|
await sync();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions }
|
||||||
|
@ -38,10 +38,19 @@ export function useAppContext(websocket) {
|
|||||||
const cardContext = useContext(CardContext);
|
const cardContext = useContext(CardContext);
|
||||||
|
|
||||||
const setSession = (token) => {
|
const setSession = (token) => {
|
||||||
|
try {
|
||||||
accountContext.actions.setToken(token);
|
accountContext.actions.setToken(token);
|
||||||
profileContext.actions.setToken(token);
|
profileContext.actions.setToken(token);
|
||||||
cardContext.actions.setToken(token);
|
cardContext.actions.setToken(token);
|
||||||
channelContext.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);
|
setWebsocket(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
112
net/web/test/Account.test.js
Normal file
112
net/web/test/Account.test.js
Normal 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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -68,8 +68,6 @@ beforeEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const mockFetch = jest.fn().mockImplementation((url, options) => {
|
const mockFetch = jest.fn().mockImplementation((url, options) => {
|
||||||
|
|
||||||
console.log(url, options);
|
|
||||||
const params = url.split('/');
|
const params = url.split('/');
|
||||||
if (params[1] === 'account' && options.method === 'POST') {
|
if (params[1] === 'account' && options.method === 'POST') {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
@ -119,7 +117,7 @@ test('testing app sync', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
mockWebsocket.onclose();
|
mockWebsocket.onclose('test close');
|
||||||
await new Promise(r => setTimeout(r, 1000));
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -96,8 +96,6 @@ beforeEach(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log(params, options);
|
|
||||||
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
url: 'endpoint',
|
url: 'endpoint',
|
||||||
status: 200,
|
status: 200,
|
||||||
|
@ -131,7 +131,6 @@ beforeEach(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log(params, options);
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
url: 'endpoint',
|
url: 'endpoint',
|
||||||
status: 200,
|
status: 200,
|
||||||
|
Loading…
Reference in New Issue
Block a user