From d9157e4c0886b513580214f962a5038311d72213 Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Tue, 14 Feb 2023 21:25:39 -0800 Subject: [PATCH] testing conversation context in mobile app --- app/mobile/src/context/useCardContext.hook.js | 148 ++++--- .../src/context/useChannelContext.hook.js | 45 +- .../context/useConversationContext.hook.js | 62 +-- .../src/context/useStoreContext.hook.js | 5 +- app/mobile/test/Conversation.test.js | 410 +++++++++++++++++- app/mobile/test/useTestStoreContext.hook.js | 15 +- 6 files changed, 565 insertions(+), 120 deletions(-) diff --git a/app/mobile/src/context/useCardContext.hook.js b/app/mobile/src/context/useCardContext.hook.js index 01e3e3ef..39c49412 100644 --- a/app/mobile/src/context/useCardContext.hook.js +++ b/app/mobile/src/context/useCardContext.hook.js @@ -66,7 +66,7 @@ export function useCardContext() { const card = cards.current.get(cardId); if (card) { card[field] = value; - cards.set(cardId, { ...card }); + cards.current.set(cardId, { ...card }); updateState({ cards: cards.current }); } }; @@ -134,27 +134,48 @@ export function useCardContext() { for (let card of delta) { if (card.data) { const item = setCardItem(card); - const entry = cards.current.get(card.id) || { card: { cardId: card.id }, channels: new Map() }; - const { profileRevision, detailRevision } = entry.card; - if (item.profileRevision !== profileRevision) { - if (item.profile) { - entry.card.profile = item.profile; - } - else { - entry.card.profile = await getCardProfile(server, token, card.id); - } - entry.card.profileRevision = item.profileRevision; - await store.actions.setCardItemProfile(guid, card.id, entry.card.profileRevision, entry.card.profile); - } - if (item.detailRevision !== detailRevision) { + const entry = cards.current.get(card.id) || { channels: new Map() }; + if (!entry.card) { + const { cardId, detailRevision, profileRevision } = item; + const entryCard = { cardId, detailRevision, profileRevision }; if (item.detail) { - entry.card.detail = item.detail; + entryCard.detail = item.detail; } else { - entry.card.detail = await getCardDetail(server, token, card.id); + entryCard.detail = await getCardDetail(server, token, card.id); + } + if (item.profile) { + entryCard.profile = item.profile; + } + else { + entryCard.profile = await getCardProfile(server, token, card.id); + } + await store.actions.setCardItem(guid, card.id, entryCard); + entry.card = entryCard; + cards.current.set(card.id, entry); + } + else { + const { profileRevision, detailRevision } = entry.card; + if (item.profileRevision !== profileRevision) { + if (item.profile) { + entry.card.profile = item.profile; + } + else { + entry.card.profile = await getCardProfile(server, token, card.id); + } + entry.card.profileRevision = item.profileRevision; + await store.actions.setCardItemProfile(guid, card.id, entry.card.profileRevision, entry.card.profile); + } + if (item.detailRevision !== detailRevision) { + if (item.detail) { + entry.card.detail = item.detail; + } + else { + entry.card.detail = await getCardDetail(server, token, card.id); + } + entry.card.detailRevision = item.detailRevision; + await store.actions.setCardItemDetail(guid, card.id, entry.card.detailRevision, entry.card.detail); } - entry.card.detailRevision = item.detailRevision; - await store.actions.setCardItemDetail(guid, card.id, entry.card.detailRevision, entry.card.detail); } if (entry.card.detail?.status === 'connected' && !entry.card.offsync) { try { @@ -168,7 +189,7 @@ export function useCardContext() { await store.action.setCardItemOffsync(guid, card.id); } } - cards.current.set(card.id, entry); + cards.current.set(card.id, { ...entry }); } else { const entry = cards.current.get(card.id) || { card: {}, channels: new Map() }; @@ -223,31 +244,42 @@ export function useCardContext() { for (let channel of delta) { if (channel.data) { const channelItem = setCardChannelItem(channel); - const channelEntry = entry.channels.get(channel.id) || { channelId: channel.id }; - const { detailRevision, topicRevision } = channelEntry; - if (channelItem.detailRevision !== detailRevision) { - if (channelItem.detail) { - channelEntry.detail = channelItem.detail; + const channelEntry = entry.channels.get(channel.id); + if (!channelEntry) { + if (!channelItem.detail) { + channelItem.detail = await getContactChannelDetail(cardServer, cardToken, channel.id); } - else { - channelEntry.detail = await getContactChannelDetail(cardServer, cardToken, channel.id); + if (!channelItem.summary) { + channelItem.summary = await getContactChannelSummary(cardServer, cardToken, channel.id); } - channelEntry.unsealedDetail = null; - channelEntry.detailRevision = channelItem.detailRevision; - await store.actions.setCardChannelItemDetail(guid, cardId, channel.id, channelItem.detailRevision, channelEntry.detail); + await store.actions.setCardChannelItem(guid, cardId, channelItem); + entry.channels.set(channel.id, { ...channelItem }); } - if (channelItem.topicRevision !== topicRevision) { - if (channelItem.summary) { - channelEntry.summary = channelItem.summary; + else { + if (channelItem.detailRevision !== channelEntry.detailRevision) { + if (channelItem.detail) { + channelEntry.detail = channelItem.detail; + } + else { + channelEntry.detail = await getContactChannelDetail(cardServer, cardToken, channel.id); + } + channelEntry.unsealedDetail = null; + channelEntry.detailRevision = channelItem.detailRevision; + await store.actions.setCardChannelItemDetail(guid, cardId, channel.id, channelEntry.detailRevision, channelEntry.detail); } - else { - channelEntry.summary = await getContactChannelSummary(cardServer, cardToken, channel.id); + if (channelItem.topicRevision !== channelEntry.topicRevision) { + if (channelItem.summary) { + channelEntry.summary = channelItem.summary; + } + else { + channelEntry.summary = await getContactChannelSummary(cardServer, cardToken, channel.id); + } + channelEntry.unsealedSummary = null; + channelEntry.topicRevision = channelItem.topicRevision; + await store.actions.setCardChannelItemSummary(guid, cardId, channel.id, channelEntry.topicRevision, channelEntry.summary); } - channelEntry.unsealedSummary = null; - channelEntry.topicRevision = channelItem.topicRevision; - await store.actions.setCardChannelItemSummary(guid, cardId, channel.id, channelItem.topicRevision, channelEntry.summary); + entry.channels.set(channel.id, { ...channelEntry }); } - entry.channels.set(channel.id, channelEntry); } else { await store.actions.clearCardChannelTopicItems(guid, cardId, channel.id); @@ -271,14 +303,12 @@ export function useCardContext() { cards.current = new Map(); const cardItems = await store.actions.getCardItems(session.guid); for(card of cardItems) { - cards.current.set(card.cardId, { card, channels: new Map() }); - } - const cardChannelItems = await store.actions.getCardChannelItems(session.guid); - for (cardChannel of cardChannelItems) { - const card = cards.current.get(cardChannel.cardId); - if (card) { - card.channels.set(card.channelId, cardChannel); + const entry = { card, channels: new Map() }; + const cardChannelItems = await store.actions.getCardChannelItems(session.guid, card.cardId); + for (cardChannel of cardChannelItems) { + entry.channels.set(cardChannel.channelId, cardChannel); } + cards.current.set(card.cardId, entry); } const status = await store.actions.getCardRequestStatus(session.guid); const revision = await store.actions.getCardRevision(session.guid); @@ -362,27 +392,27 @@ export function useCardContext() { } }, removeTopic: async (cardId, channelId, topicId) => { - const { detail, profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; const cardToken = `${profile?.guid}.${detail?.token}`; return await removeContactChannelTopic(profile?.node, cardToken, channelId, topicId); }, setTopicSubject: async (cardId, channelId, topicId, type, subject) => { - const { detail, profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; const cardToken = `${profile?.guid}.${detail?.token}`; return await setContactChannelTopicSubject(profile?.node, cardToken, channelId, topicId, type, subject); }, getTopicAssetUrl: (cardId, channelId, topicId, assetId) => { - const { detail, profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; const cardToken = `${profile?.guid}.${detail?.token}`; return getContactChannelTopicAssetUrl(profile?.node, cardToken, channelId, topicId, assetId); }, getTopics: async (cardId, channelId, revision, count, begin, end) => { - const { detail, profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; const cardToken = `${profile?.guid}.${detail?.token}`; return await getContactChannelTopics(profile?.node, cardToken, channelId); }, - getChannelTopic: async (cardId, channelId, topicId) => { - const { detail, profile } = cards.current.get(cardId) || {}; + getTopic: async (cardId, channelId, topicId) => { + const { detail, profile } = (cards.current.get(cardId) || {}).card; const cardToken = `${profile?.guid}.${detail?.token}`; return await getContactChannelTopic(profile?.node, cardToken, channelId, topicId); }, @@ -394,22 +424,22 @@ export function useCardContext() { setChannelReadRevision: async (cardId, channelId, revision) => { const { guid } = access.current; await store.actions.setCardChannelItemReadRevision(guid, cardId, channelId, revision); - setCardField(cardId, 'readRevision', revision); + setCardChannelField(cardId, channelId, 'readRevision', revision); }, setChannelSyncRevision: async (cardId, channelId, revision) => { const { guid } = access.current; await store.actions.setCardChannelItemSyncRevision(guid, cardId, channelId, revision); - setCardField(cardId, 'syncRevision', revision); + setCardChannelField(cardId, channelId, 'syncRevision', revision); }, setChannelTopicMarker: async (cardId, channelId, marker) => { const { guid } = access.current; await store.actions.setCardChannelItemTopicMarker(guid, cardId, channelId, marker); - setCardField(cardId, 'topicMarker', marker); + setCardChannelField(cardId, channelId, 'topicMarker', marker); }, setChannelMarkerAndSync: async (cardId, channelId, marker, revision) => { const { guid } = access.current; await store.actions.setCardChannelItemMarkerAndSync(guid, cardId, channelId, marker, revision); - setCardField(cardId, 'topicMarker', marker, 'syncRevision', revision); + setCardChannelField(cardId, channelId, 'topicMarker', marker, 'syncRevision', revision); }, setCardFlag: async (cardId) => { const { guid } = acccess.current; @@ -440,20 +470,20 @@ export function useCardContext() { await store.actions.setCardChannelTopicBlocked(guid, cardId, channelId, topicId, false); }, addChannelAlert: async (cardId, channelId) => { - const { profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; return await addFlag(profile?.node, profile?.guid, channelId); }, addTopicAlert: async (cardId, channelId, topicId) => { - const { detail, profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; return await addFlag(profile?.node, profile?.guid, channelId, topicId); }, getChannelNotifications: async (cardId, channelId) => { - const { detail, profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; const token = `${profile?.guid}.${detail?.token}`; return await getContactChannelNotifications(profile?.node, token, channelId); }, setChannelNotifications: async (cardId, channelId, notify) => { - const { detail, profile } = cards.current.get(cardId) || {}; + const { detail, profile } = (cards.current.get(cardId) || {}).card; const token = `${profile?.guid}.${detail?.token}`; return await setContactChannelNotifications(profile?.node, token, channelId, notify); }, diff --git a/app/mobile/src/context/useChannelContext.hook.js b/app/mobile/src/context/useChannelContext.hook.js index 0a6270ff..daeddf68 100644 --- a/app/mobile/src/context/useChannelContext.hook.js +++ b/app/mobile/src/context/useChannelContext.hook.js @@ -48,12 +48,12 @@ export function useChannelContext() { } const setChannelField = (channelId, field, value, field2, value2) => { - const channel = channels.get(channelId) || {}; + const channel = channels.current.get(channelId) || {}; channel[field] = value; if (field2) { channel[field2] = value2; } - channels.set(channelId, { ...channel }); + channels.current.set(channelId, { ...channel }); updateState({ channels: channels.current }); }; @@ -67,30 +67,31 @@ export function useChannelContext() { for (let channel of delta) { if (channel.data) { const item = setChannelItem(channel); - if (item.detail && item.summary) { + const entry = channels.current.get(channel.id); + if (!entry) { + if (!item.detail) { + item.detail = await getChannelDetail(server, token, channel.id); + } + if (!item.summary) { + item.summary = await getChannelSummary(server, token, channel.id); + } await store.actions.setChannelItem(guid, item); - channels.current.set(item.channelId, item); + channels.current.set(channel.id, item); } else { - const { channelId, detailRevision, topicRevision, detail, summary } = channels.current.get(channel.id) || {} - if (item.detailRevision !== detailRevision) { - item.detailRevision = detailRevision; - item.detail = await getChannelDetail(server, token, channelId); - await store.actions.setChannelItemDetail(guid, channelId, detailRevision, item.detail); + if (item.detailRevision !== entry.detailRevision) { + entry.detail = await getChannelDetail(server, token, channel.id); + entry.unsealedDetail = null; + entry.detailRevision = item.detailRevision; + await store.actions.setChannelItemDetail(guid, channel.id, entry.detailRevision, entry.detail); } - else { - item.datail = detail; + if (item.topicRevision !== entry.topicRevision) { + entry.summary = await getChannelSummary(server, token, channel.id); + entry.unsealedSummary = null; + entry.topicRevision = item.topicRevision; + await store.actions.setChannelItemSummary(guid, channel.id, entry.topicRevision, entry.summary); } - if (item.topicRevision !== topicRevision) { - item.topicRevision = topicRevision; - item.summary = await getChannelSummary(server, token, item.channelId); - await store.actions.setChannelItemSummary(guid, channelId, topicRevision, item.summary); - } - else { - item.summary = summary; - } - await store.actions.setChannelItem(guid, item); - channels.current.set(channelId, item); + channels.current.set(channel.id, { ...entry }); } } else { @@ -192,7 +193,7 @@ export function useChannelContext() { const { server, token } = access.current; getChannelTopicAssetUrl(server, token, channelId, topicId, assetId); }, - getTopics: async (channelId) => { + getTopics: async (channelId, revision, count, begin, end) => { const { server, token } = access.current; return await getChannelTopics(server, token, channelId, revision, count, begin, end); }, diff --git a/app/mobile/src/context/useConversationContext.hook.js b/app/mobile/src/context/useConversationContext.hook.js index 29846397..b0d66b95 100644 --- a/app/mobile/src/context/useConversationContext.hook.js +++ b/app/mobile/src/context/useConversationContext.hook.js @@ -33,11 +33,11 @@ export function useConversationContext() { } const sync = async () => { - if (!syncing.current && (reset.current || update.current || force.current || more.current)) { + if (!syncing.current && (reset.current || update.current || force.current || more.current)) { const loadMore = more.current; const ignoreRevision = force.current; - const conversation = converstaionId.current; + const conversation = conversationId.current; let curRevision, setRevision, marker; syncing.current = true; @@ -55,9 +55,11 @@ export function useConversationContext() { if (conversation) { const { cardId, channelId } = conversation; const cardValue = cardId ? card.state.cards.get(cardId) : null; - const channelValue = cardId ? cardValue?.get(channelId) : channel.state.channels.get(channelId); + const channelValue = cardId ? cardValue?.channels.get(channelId) : channel.state.channels.get(channelId); + if (channelValue) { const { topicRevision, syncRevision, topicMarker } = channelValue; + curRevision = topicRevision; setRevision = syncRevision; marker = topicMarker; @@ -78,33 +80,35 @@ export function useConversationContext() { return; } - try { - if (!marker) { - const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, null); - await setTopicDelta(cardId, channelId, delta.topics); - setMarkerAndSync(cardId, channelId, topicMarker, topicRevision); + if (ignoreRevision || curRevision !== setRevision) { + try { + if (!marker) { + const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, null); + await setTopicDelta(cardId, channelId, delta.topics); + await setMarkerAndSync(cardId, channelId, delta.marker, curRevision); + } + if (loadMore && marker) { + const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, marker); + await setTopicDelta(cardId, channelId, delta.topics); + await setTopicMarker(cardId, channelId, delta.marker); + } + if (ignoreRevision || curRevision !== setRevision) { + const delta = await getTopicDelta(cardId, channelId, setRevision, null, marker, null); + await setTopicDelta(cardId, channelId, delta.topics); + await setSyncRevision(cardId, channelId, curRevision); + } } - if (loadMore && marker) { - const delta = await getTopicDelta(cardId, channelId, null, COUNT, null, marker); - await setTopicDelta(cardId, channelId, delta.topics); - setTopicMarker(cardId, channelId, delta.topicMarker); - } - if (ignoreRevision || curTopicRevision.current !== setTopicRevision.current) { - const delta = await getTopicDelta(cardId, channelId, setRevision, null, marker, null); - await setTopicDelta(cardId, channelId, delta.topics); - setSyncRevision(cardid, channelId, delta.topicRevision); + catch(err) { + console.log(err); + updateState({ offysnc: true }); + syncing.current = false; + return } } - catch(err) { - console.log(err); - updateState({ offysnc: true }); - syncing.current = false; - return - } - - syncing.current = false; - await sync(); } + + syncing.current = false; + await sync(); } } @@ -354,7 +358,7 @@ export function useConversationContext() { if (cardId) { return await card.actions.setChannelSyncRevision(cardId, channelId, revision); } - return await channel.actions.setSyncRevision(channelid, revision); + return await channel.actions.setSyncRevision(channelId, revision); } const setMarkerAndSync = async (cardId, channelId, marker, revision) => { @@ -378,7 +382,7 @@ export function useConversationContext() { return await channel.actions.getTopic(channelId, topicId); } - const mapTopicItem = (entry) => { + const mapTopicEntry = (entry) => { return { topicId: entry.id, revision: entry.revision, @@ -392,7 +396,7 @@ export function useConversationContext() { if (topic) { topic[field] = value; } - topics.current.set(topicId, topic); + topics.current.set(topicId, { ...topic }); updateState({ topics: topics.current }); }; diff --git a/app/mobile/src/context/useStoreContext.hook.js b/app/mobile/src/context/useStoreContext.hook.js index 86c1d1d6..83457215 100644 --- a/app/mobile/src/context/useStoreContext.hook.js +++ b/app/mobile/src/context/useStoreContext.hook.js @@ -296,10 +296,9 @@ export function useStoreContext() { setCardChannelItemUnsealedSummary: async (guid, cardId, channelId, revision, unsealed) => { await db.current.executeSql(`UPDATE card_channel_${guid} set unsealed_summary=? where topic_revision=? AND card_id=? AND channel_id=?`, [encodeObject(unsealed), revision, cardId, channelId]); }, - getCardChannelItems: async (guid) => { - const values = await getAppValues(db.current, `SELECT card_id, channel_id, read_revision, sync_revision, revision, blocked, detail_revision, topic_revision, topic_marker, detail, unsealed_detail, summary, unsealed_summary FROM card_channel_${guid}`, []); + getCardChannelItems: async (guid, cardId) => { + const values = await getAppValues(db.current, `SELECT channel_id, read_revision, sync_revision, revision, blocked, detail_revision, topic_revision, topic_marker, detail, unsealed_detail, summary, unsealed_summary FROM card_channel_${guid} where card_id=?`, [cardId]); return values.map(channel => ({ - cardId: channel.card_id, channelId: channel.channel_id, revision: channel.revision, readRevision: channel.read_revision, diff --git a/app/mobile/test/Conversation.test.js b/app/mobile/test/Conversation.test.js index 5a85b618..78a28e03 100644 --- a/app/mobile/test/Conversation.test.js +++ b/app/mobile/test/Conversation.test.js @@ -19,11 +19,16 @@ function ConversationView() { useEffect(() => { setRenderCount(renderCount + 1); const rendered = []; + conversation.state.topics.forEach((value) => { + rendered.push({ value.detail.data }); + }); + setTopics(rendered); }, [conversation.state]); return ( + { topics } ); } @@ -40,10 +45,20 @@ function ConversationTestApp() { ) } +let fetchCards; +let fetchChannels; +let fetchCardChannels; +let fetchTopics; + const realUseContext = React.useContext; const realFetchWithTimeout = fetchUtil.fetchWithTimeout; const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout; beforeEach(() => { + + fetchCards = []; + fetchChannels = []; + fetchCardChannels = []; + const mockUseContext = jest.fn().mockImplementation((ctx) => { if (ctx === StoreContext) { return useTestStoreContext(); @@ -53,9 +68,39 @@ beforeEach(() => { React.useContext = mockUseContext; const mockFetch = jest.fn().mockImplementation((url, options) => { - return Promise.resolve({ - json: () => Promise.resolve([]) - }); + + if (url.startsWith('https://test.org/content/channels?agent')) { + return Promise.resolve({ + json: () => Promise.resolve(fetchChannels) + }); + } + else if (url.startsWith('https://test.org/contact/cards?agent')) { + return Promise.resolve({ + json: () => Promise.resolve(fetchCards) + }); + } + else if (url.startsWith('https://test.org/content/channels?contact')) { + return Promise.resolve({ + json: () => Promise.resolve(fetchCardChannels) + }); + } + else if (url.startsWith('https://test.org/content/channels/aabb/topics?contact') || + url.startsWith('https://test.org/content/channels/123/topics?agent')) { + const headers = new Map(); + headers.set('topic-marker', 48); + headers.set('topic-revision', 55); + return Promise.resolve({ + url: 'getTopics', + status: 200, + headers: headers, + json: () => Promise.resolve(fetchTopics), + }); + } + else { + return Promise.resolve({ + json: () => Promise.resolve([]) + }); + } }); fetchUtil.fetchWithTimeout = mockFetch; fetchUtil.fetchWithCustomTimeout = mockFetch; @@ -67,7 +112,7 @@ afterEach(() => { fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout; }); -test('test conversation', async () => { +test('add, update, remove card channel topic', async () => { render() @@ -81,5 +126,362 @@ test('test conversation', async () => { await card.actions.setRevision(1); //const conversation = screen.getByTestId('conversation').props.conversation; }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(0); + }); + + fetchChannels = [ + { id: '123', revision: 2, data: { + detailRevision: 3, + topicRevision: 5, + channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testdata' }, + channelDetail: { dataType: 'superbasic', data: 'testdata' }, + } + }, + ]; + + fetchCards = [{ + id: '000a', + revision: 1, + data: { + detailRevision: 2, + profileRevision: 3, + notifiedProfile: 3, + notifiedArticle: 5, + notifiedChannel: 6, + notifiedView: 7, + cardDetail: { status: 'connected', statusUpdate: 136, token: '01ab', }, + cardProfile: { guid: '01ab23', handle: 'test1', name: 'tester', imageSet: false, + seal: 'abc', version: '1.1.1', node: 'test.org' }, + }, + }]; + + fetchCardChannels = [ + { id: 'aabb', revision: 2, data: { + detailRevision: 3, + topicRevision: 5, + channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testcardtopic' }, + channelDetail: { dataType: 'superbasic', data: 'testcardchannel' }, + } + }, + ]; + + fetchTopics = [ + { id: '888', revision: 5, data: { + detailRevision: 3, + tagRevision: 0, + topicDetail: { + guid: '0123', + dataType: 'topictype', + data: 'contacttopicdata', + created: 1, + updated: 1, + status: 'confirmed', + transform: 'complete', + }, + } + } + ]; + + await act(async () => { + const conversation = screen.getByTestId('conversation').props.conversation; + conversation.actions.setConversation('000a', 'aabb'); + + const channel = screen.getByTestId('conversation').props.channel; + await channel.actions.setRevision(2); + const card = screen.getByTestId('conversation').props.card; + await card.actions.setRevision(2); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(1); + expect(screen.getByTestId('888').props.children).toBe('contacttopicdata'); + }); + + fetchCards = [{ + id: '000a', + revision: 2, + data: { + detailRevision: 2, + profileRevision: 3, + notifiedProfile: 3, + notifiedArticle: 5, + notifiedChannel: 7, + notifiedView: 7, + }, + }]; + + fetchCardChannels = [ + { id: 'aabb', revision: 3, data: { + detailRevision: 3, + topicRevision: 6, + } + }, + ]; + + fetchTopics = [ + { id: '888', revision: 6, data: { + detailRevision: 4, + tagRevision: 0, + topicDetail: { + guid: '0123', + dataType: 'topictype', + data: 'contacttopicdata2', + created: 1, + updated: 1, + status: 'confirmed', + transform: 'complete', + }, + } + } + ]; + + await act(async () => { + const card = screen.getByTestId('conversation').props.card; + await card.actions.setRevision(3); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(1); + expect(screen.getByTestId('888').props.children).toBe('contacttopicdata2'); + }); + + fetchCards = [{ + id: '000a', + revision: 3, + data: { + detailRevision: 2, + profileRevision: 3, + notifiedProfile: 3, + notifiedArticle: 5, + notifiedChannel: 8, + notifiedView: 7, + }, + }]; + + fetchCardChannels = [ + { id: 'aabb', revision: 4, data: { + detailRevision: 3, + topicRevision: 6, + } + }, + ]; + + fetchTopics = [ + { id: '888', revision: 6 } + ]; + + await act(async () => { + const card = screen.getByTestId('conversation').props.card; + await card.actions.setRevision(4); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(1); + }); + + + fetchCards = [{ + id: '000a', + revision: 4, + data: { + detailRevision: 2, + profileRevision: 3, + notifiedProfile: 3, + notifiedArticle: 5, + notifiedChannel: 9, + notifiedView: 7, + }, + }]; + + fetchCardChannels = [ + { id: 'aabb', revision: 5, data: { + detailRevision: 3, + topicRevision: 7, + } + }, + ]; + + await act(async () => { + const card = screen.getByTestId('conversation').props.card; + await card.actions.setRevision(5); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(0); + }); + + + +}); + + + + + + +test('add, update, remove channel topic', async () => { + + render() + + 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; + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(0); + }); + + fetchChannels = [ + { id: '123', revision: 2, data: { + detailRevision: 3, + topicRevision: 5, + channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testdata' }, + channelDetail: { dataType: 'superbasic', data: 'testdata' }, + } + }, + ]; + + fetchCards = [{ + id: '000a', + revision: 1, + data: { + detailRevision: 2, + profileRevision: 3, + notifiedProfile: 3, + notifiedArticle: 5, + notifiedChannel: 6, + notifiedView: 7, + cardDetail: { status: 'connected', statusUpdate: 136, token: '01ab', }, + cardProfile: { guid: '01ab23', handle: 'test1', name: 'tester', imageSet: false, + seal: 'abc', version: '1.1.1', node: 'test.org' }, + }, + }]; + + fetchCardChannels = [ + { id: 'aabb', revision: 2, data: { + detailRevision: 3, + topicRevision: 5, + channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testcardtopic' }, + channelDetail: { dataType: 'superbasic', data: 'testcardchannel' }, + } + }, + ]; + + fetchTopics = [ + { id: '888', revision: 5, data: { + detailRevision: 3, + tagRevision: 0, + topicDetail: { + guid: '0123', + dataType: 'topictype', + data: 'contacttopicdata', + created: 1, + updated: 1, + status: 'confirmed', + transform: 'complete', + }, + } + } + ]; + + await act(async () => { + const conversation = screen.getByTestId('conversation').props.conversation; + conversation.actions.setConversation(null, '123'); + + const channel = screen.getByTestId('conversation').props.channel; + await channel.actions.setRevision(2); + const card = screen.getByTestId('conversation').props.card; + await card.actions.setRevision(2); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(1); + expect(screen.getByTestId('888').props.children).toBe('contacttopicdata'); + }); + + fetchChannels = [ + { id: '123', revision: 3, data: { + detailRevision: 3, + topicRevision: 6, + } + }, + ]; + + fetchTopics = [ + { id: '888', revision: 7, data: { + detailRevision: 5, + tagRevision: 0, + topicDetail: { + guid: '0123', + dataType: 'topictype', + data: 'contacttopicdata2', + created: 1, + updated: 1, + status: 'confirmed', + transform: 'complete', + }, + } + } + ]; + + await act(async () => { + const channel = screen.getByTestId('conversation').props.channel; + await channel.actions.setRevision(3); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(1); + expect(screen.getByTestId('888').props.children).toBe('contacttopicdata2'); + }); + + fetchChannels = [ + { id: '123', revision: 4, data: { + detailRevision: 3, + topicRevision: 6, + } + }, + ]; + + fetchTopics = [ + { id: '888', revision: 8 } + ]; + + await act(async () => { + const channel = screen.getByTestId('conversation').props.channel; + await channel.actions.setRevision(4); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(1); + }); + + fetchChannels = [ + { id: '123', revision: 5, data: { + detailRevision: 3, + topicRevision: 7, + } + }, + ]; + + await act(async () => { + const channel = screen.getByTestId('conversation').props.channel; + await channel.actions.setRevision(5); + }); + + await waitFor(async () => { + expect(screen.getByTestId('conversation').props.children).toHaveLength(0); + }); + + + }); diff --git a/app/mobile/test/useTestStoreContext.hook.js b/app/mobile/test/useTestStoreContext.hook.js index 477df2ff..cd58cfd6 100644 --- a/app/mobile/test/useTestStoreContext.hook.js +++ b/app/mobile/test/useTestStoreContext.hook.js @@ -123,6 +123,8 @@ export function useTestStoreContext() { }, setChannelItemTopicMarker: async (guid, channelId, marker) => { }, + setChannelItemMarkerAndSync: async (guid, channelId, marker, revision) => { + }, setChannelItemBlocked: async (guid, channelId) => { }, clearChannelItemBlocked: async (guid, channelId) => { @@ -143,6 +145,7 @@ export function useTestStoreContext() { }, getChannelTopicItems: async (guid, channelId) => { + return []; }, setChannelTopicItem: async (guid, channelId, topic) => { }, @@ -158,7 +161,9 @@ export function useTestStoreContext() { }, setCardChannelItem: async (guid, cardId, channel) => { - cardChannelItems.current.set(`${cardId}:${channel.channelId}`, channel); + const card = cardChannels.current.get(cardId) || new Map(); + card.set(channel.channelId, channel); + cardChannels.current.set(cardId, card); }, clearCardChannelItem: async (guid, cardId, channelId) => { }, @@ -170,6 +175,8 @@ export function useTestStoreContext() { }, setCardChannelItemTopicMarker: async (guid, cardId, channelId, marker) => { }, + setCardChannelItemMarkerAndSync: async (guid, cardid, channelId, marker, revision) => { + }, setCardChannelItemDetail: async (guid, cardId, channelId, revision, detail) => { }, setCardChannelItemUnsealedDetail: async (guid, cardId, channelId, revision, unsealed) => { @@ -180,13 +187,15 @@ export function useTestStoreContext() { }, getCardChannelItemView: async (guid, cardId, channelId) => { }, - getCardChannelItems: async (guid) => { - return Array.from(cardChannels.current.values()); + getCardChannelItems: async (guid, cardId) => { + const card = cardChannels.current.get(cardId) || new Map(); + return Array.from(card.values()); }, clearCardChannelItems: async (guid, cardId) => { }, getCardChannelTopicItems: async (guid, cardId, channelId) => { + return []; }, setCardChannelTopicItem: async (guid, cardId, channelId, topic) => { },