testing conversation context for mobile app

This commit is contained in:
Roland Osborne 2023-02-13 21:53:44 -08:00
parent eca43835be
commit 50fa8bf9af
4 changed files with 125 additions and 64 deletions

View File

@ -109,6 +109,7 @@ export function useCardContext() {
const { notifiedView, notifiedProfile, notifiedArticle, notifiedChannel } = card.data || {};
const cardRevision = { view: notifiedView, profile: notifiedProfile, artcile: notifiedArticle, channel: notifiedChannel };
await syncCard(server, token, guid, entry, cardRevision);
await store.action.clearCardItemOffsync(guid, cardId);
entry.card.offsync = false;
}
@ -164,6 +165,7 @@ export function useCardContext() {
catch (err) {
console.log(err);
entry.offsync = true;
await store.action.setCardItemOffsync(guid, card.id);
}
}
cards.current.set(card.id, entry);

View File

@ -24,7 +24,6 @@ export function useConversationContext() {
const force = useRef(false);
const syncing = useRef(false);
const update = useRef(false);
const loaded = useRef(false);
const conversationId = useRef(null);
const topics = useRef(new Map());
@ -44,7 +43,7 @@ export function useConversationContext() {
syncing.current = true;
update.current = false;
force.current = false;
loadMore.current = false;
more.current = false;
if (reset.current) {
reset.current = false;
@ -55,8 +54,6 @@ export function useConversationContext() {
if (conversation) {
const { cardId, channelId } = conversation;
if (loaded.current) {
const cardValue = cardId ? card.state.cards.get(cardId) : null;
const channelValue = cardId ? cardValue?.get(channelId) : channel.state.channels.get(channelId);
if (channelValue) {
@ -65,35 +62,21 @@ export function useConversationContext() {
setRevision = syncRevision;
marker = topicMarker;
updateState({ card: cardValue, channel: channelValue });
}
else {
console.log("failed to load conversation");
sysncing.current = false;
return;
}
}
if (!loaded.current) {
const cardValue = cardId ? card.state.cards.get(cardId) : null;
const channelValue = cardId ? cardValue?.get(channelId) : channel.state.channels.get(channelId);
if (channelValue) {
const { topicRevision, syncRevision, topicMarker } = channelValue;
curRevision = topicRevision;
setRevision = syncRevision;
marker = topicMarker;
const topicItems = await getTopicItems(cardId, channelId);
for (let topic: topicItems) {
for (let topic of topicItems) {
topics.current.set(topic.topicId, topic);
}
updateState({ card: cardValue, channel: channelValue, topics: topics.current });
updateState({ offsync: false, topics: topics.current });
loaded.current = true;
}
}
else {
console.log("failed to load conversation");
syncing.current = false;
return;
}
}
try {
if (!marker) {
@ -125,7 +108,7 @@ export function useConversationContext() {
}
}
const setTopicDelta(cardId, channelId, entries) => {
const setTopicDelta = async (cardId, channelId, entries) => {
for (let entry of entries) {
if (entry.data) {
if (entry.data.detail) {
@ -139,6 +122,7 @@ export function useConversationContext() {
}
}
else {
topics.current.delete(entry.id);
clearTopicItem(entry.id);
}
}
@ -157,7 +141,7 @@ export function useConversationContext() {
reset.current = true;
await sync();
},
clearConversation: async ()
clearConversation: async () => {
conversationId.current = null;
reset.current = true;
await sync();
@ -216,6 +200,15 @@ export function useConversationContext() {
await channel.actions.clearChannelCard(channelId, id);
}
},
setChannelReadRevision: async (revision) => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
await card.actions.setChannelReadRevision(cardId, channelId, revision);
}
else if (channelId) {
await channel.actions.setReadRevision(channelId, revision);
}
},
addChannelAlert: async () => {
const { cardId, channelId } = conversationId.current || {};
if (cardId) {
@ -224,7 +217,6 @@ export function useConversationContext() {
else if (channelId) {
return await channel.actions.addChannelAlert(channelId);
}
}
},
setChannelFlag: async () => {
const { cardId, channelId } = conversationId.current || {};
@ -271,7 +263,7 @@ export function useConversationContext() {
if (cardId) {
await card.actions.setUnsealedTopicSubject(cardId, channelId, topicId, revision, unsealed);
}
else {channelId) {
else if (channelId) {
await channel.actions.setUnsealedTopicSubject(channelId, topicId, revision, unsealed);
}
setTopicField(topicId, 'unsaledDetail', unsealed);
@ -390,8 +382,8 @@ export function useConversationContext() {
return {
topicId: entry.id,
revision: entry.revision,
detailRevision = entry.data?.detailRevision,
detail = entry.data?.topicDetail,
detailRevision: entry.data?.detailRevision,
detail: entry.data?.topicDetail,
};
};

View File

@ -103,7 +103,7 @@ export function useStoreContext() {
},
setCardItem: async (guid, card) => {
const { id, revision, data } = card;
await db.current.executeSql(`INSERT OR REPLACE INTO card_${guid} (card_id, revision, detail_revision, profile_revision, detail, profile, notified_view, notified_profile, notified_article, notified_channel) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`, [id, revision, data.detailRevision, data.profileRevision, encodeObject(data.cardDetail), encodeObject(data.cardProfile), null, null, null, null]);
await db.current.executeSql(`INSERT OR REPLACE INTO card_${guid} (card_id, revision, detail_revision, profile_revision, detail, profile, notified_view, notified_profile, notified_article, notified_channel) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`, [card.cardId, card.revision, card.detailRevision, card.profileRevision, encodeObject(card.detail), encodeObject(card.profile), null, null, null, null]);
},
clearCardItem: async (guid, cardId) => {
await db.current.executeSql(`DELETE FROM card_${guid} WHERE card_id=?`, [cardId]);
@ -141,24 +141,6 @@ export function useStoreContext() {
setCardItemProfile: async (guid, cardId, revision, profile) => {
await db.current.executeSql(`UPDATE card_${guid} set profile_revision=?, profile=? where card_id=?`, [revision, encodeObject(profile), cardId]);
},
getCardItemStatus: async (guid, cardId) => {
const values = await getAppValues(db.current, `SELECT detail, profile, profile_revision, detail_revision, notified_view, notified_article, notified_profile, notified_channel, offsync FROM card_${guid} WHERE card_id=?`, [cardId]);
if (!values.length) {
return null;
}
return {
detail: decodeObject(values[0].detail),
profile: decodeObject(values[0].profile),
profileRevision: values[0].profile_revision,
detailRevision: values[0].detail_revision,
notifiedView: values[0].notified_view,
notifiedArticle: values[0].notified_article,
notifiedProfile: values[0].notified_profile,
notifiedChannel: values[0].notified_channel,
offsync: values[0].offsync,
blocked: values[0].blocked,
};
},
getCardItems: async (guid) => {
const values = await getAppValues(db.current, `SELECT card_id, revision, detail_revision, profile_revision, detail, profile, offsync, blocked, notified_view, notified_profile, notified_article, notified_channel FROM card_${guid}`, []);
return values.map(card => ({

View File

@ -0,0 +1,85 @@
import React, { useState, useEffect, useContext } from 'react';
import { View, Text } from 'react-native';
import { useTestStoreContext } from './useTestStoreContext.hook';
import { prettyDOM } from '@testing-library/dom';
import {render, act, screen, waitFor, fireEvent} from '@testing-library/react-native';
import { StoreContext } from 'context/StoreContext';
import { ConversationContextProvider, ConversationContext } from 'context/ConversationContext';
import { CardContextProvider, CardContext } from 'context/CardContext';
import { ChannelContextProvider, ChannelContext } from 'context/ChannelContext';
import * as fetchUtil from 'api/fetchUtil';
function ConversationView() {
const [renderCount, setRenderCount] = useState(0);
const conversation = useContext(ConversationContext);
const channel = useContext(ChannelContext);
const card = useContext(CardContext);
const [topics, setTopics] = useState([]);
useEffect(() => {
setRenderCount(renderCount + 1);
const rendered = [];
}, [conversation.state]);
return (
<View key="conversation" testID="conversation" renderCount={renderCount}
card={card} channel={channel} conversation={conversation}>
</View>
);
}
function ConversationTestApp() {
return (
<ChannelContextProvider>
<CardContextProvider>
<ConversationContextProvider>
<ConversationView />
</ConversationContextProvider>
</CardContextProvider>
</ChannelContextProvider>
)
}
const realUseContext = React.useContext;
const realFetchWithTimeout = fetchUtil.fetchWithTimeout;
const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout;
beforeEach(() => {
const mockUseContext = jest.fn().mockImplementation((ctx) => {
if (ctx === StoreContext) {
return useTestStoreContext();
}
return realUseContext(ctx);
});
React.useContext = mockUseContext;
const mockFetch = jest.fn().mockImplementation((url, options) => {
return Promise.resolve({
json: () => Promise.resolve([])
});
});
fetchUtil.fetchWithTimeout = mockFetch;
fetchUtil.fetchWithCustomTimeout = mockFetch;
});
afterEach(() => {
React.useContext = realUseContext;
fetchUtil.fetchWithTimeout = realFetchWithTimeout;
fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout;
});
test('test conversation', async () => {
render(<ConversationTestApp />)
await act(async () => {
const channel = screen.getByTestId('conversation').props.channel;
await channel.actions.setSession({ guid: 'abc', server: 'test.org', token: '123' });
await channel.actions.setRevision(1);
const card = screen.getByTestId('conversation').props.card;
await card.actions.setSession({ guid: 'abc', server: 'test.org', token: '123' });
await card.actions.setRevision(1);
//const conversation = screen.getByTestId('conversation').props.conversation;
});
});