diff --git a/net/web/src/context/useConversationContext.hook.js b/net/web/src/context/useConversationContext.hook.js index 4e21122d..38c2429a 100644 --- a/net/web/src/context/useConversationContext.hook.js +++ b/net/web/src/context/useConversationContext.hook.js @@ -27,6 +27,28 @@ export function useConversationContext() { const topics = useRef(new Map()); useEffect(() => { + if (conversationId.current) { + let setChannel; + const { cardId, channelId } = conversationId.current; + if (cardId) { + const setCard = card.state.cards.get(cardId); + setChannel = setCard?.channels.get(channelId); + } + else { + setChannel = channel.state.channels.get(channelId); + } + if (setChannel) { + const { topicRevision, detailRevision } = setChannel.data; + if (curTopicRevision.current !== topicRevision || curDetailRevision.current !== detailRevision) { + curTopicRevision.current = topicRevision; + curDetailRevision.current = detailRevision; + sync(); + } + } + else { + console.log('conversation not found'); + } + } }, [card.state, channel.state]); const getTopicDelta = async (cardId, channelId, revision, count, begin, end) => { @@ -63,22 +85,22 @@ export function useConversationContext() { } } - const setChannelCard = async (cardId, channelId, cardId) => { + const setChannelCard = async (cardId, channelId, id) => { if (cardId) { console.log('cannot update channel card'); } else { - await channel.actions.setChannelCard(channelId, cardId); + await channel.actions.setChannelCard(channelId, id); await channel.actions.resync(); } } - const clearChannelCard = async (cardId, channelId, cardId) => { + const clearChannelCard = async (cardId, channelId, id) => { if (cardId) { console.log('cannot update channel card'); } else { - await channel.actions.clearChannelCard(channelId, cardId); + await channel.actions.clearChannelCard(channelId, id); await channelactions.resync(); } }; @@ -122,7 +144,7 @@ export function useConversationContext() { } }; - const resync = async () => [ + const resync = async () => { try { force.current = true; await sync(); @@ -249,13 +271,13 @@ export function useConversationContext() { const { cardId, channelId } = conversationId.current; await setChannelSubject(cardId, channelId, type, subject); }, - setChannelCard: async (cardId) => { + setChannelCard: async (id) => { const { cardId, channelId } = conversationId.current; - await setChannelCard(cardId, channelId, cardId); + await setChannelCard(cardId, channelId, id); }, - clearChannelCard: async (cardId) => { + clearChannelCard: async (id) => { const { cardId, channelId } = conversationId.current; - await clearChannelCard(cardId, channelId, cardId); + await clearChannelCard(cardId, channelId, id); }, addTopic: async (type, message, files) => { const { cardId, channelId } = conversationId.current; @@ -271,7 +293,7 @@ export function useConversationContext() { }, getTopicAssetUrl: (topicId, assetId) => { const { cardId, channelId } = conversationId.current; - return await getTopicAssetUrl(cardId, channelId, topicId, assetId); + return getTopicAssetUrl(cardId, channelId, topicId, assetId); }, unsealTopicSubject: (topicId, unsealed) => { const topic = topics.current.get(topicId); diff --git a/net/web/test/Conversation.test.js b/net/web/test/Conversation.test.js new file mode 100644 index 00000000..4e9a586b --- /dev/null +++ b/net/web/test/Conversation.test.js @@ -0,0 +1,180 @@ +import React, { useState, useEffect, useContext } from 'react'; +import { prettyDOM } from '@testing-library/dom' +import {render, act, screen, waitFor, fireEvent} from '@testing-library/react' +import { CardContextProvider, CardContext } from 'context/CardContext'; +import { ChannelContextProvider, ChannelContext } from 'context/ChannelContext'; +import { ConversationContextProvider, ConversationContext } from 'context/ConversationContext'; +import * as fetchUtil from 'api/fetchUtil'; + +let cardContext = null; +let channelContext = null; +let conversationContext = null; +function ConversationView() { + const [renderCount, setRenderCount] = useState(0); + const [topics, setTopics] = useState([]); + + const card = useContext(CardContext); + const channel = useContext(ChannelContext); + const conversation = useContext(ConversationContext); + + cardContext = card; + channelContext = channel; + conversationContext = conversation; + + useEffect(() => { + const rendered = [] + const entries = Array.from(conversation.state.topics.values()); + entries.forEach(entry => { + rendered.push( +
+ { entry.data.cardProfile.name } + { entry.data.cardDetail.status } + { entry.data.cardDetail.token } +
); + }); + setTopics(rendered); + setRenderCount(renderCount + 1); + }, [card.state]) + + return ( +
+ { topics } +
+ ); +} + +function ConversationTestApp() { + return ( + + + + + + + + ) +} + +const realFetchWithTimeout = fetchUtil.fetchWithTimeout; +const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout; + +let statusCards; +let fetchCards; +let statusChannels; +let fetchChannels; +let statusCardChannels; +let fetchCardChannels; +beforeEach(() => { + + statusCards = 200; + fetchCards = []; + statusChannels = 200; + fetchChannels = []; + statusCardChannels = 200; + fetchCardChannels = []; + + const mockFetch = jest.fn().mockImplementation((url, options) => { + const params = url.split('/'); + console.log(params, options); + if (params[2].startsWith('channels?agent')) { + return Promise.resolve({ + url: 'getChannels', + status: statusChannels, + json: () => Promise.resolve(fetchChannels), + }); + } + if (params[2].startsWith('channels?contact')) { + return Promise.resolve({ + url: 'getCardChannels', + status: statusCardChannels, + json: () => Promise.resolve(fetchCardChannels), + }); + } + else if (params[2]?.split('?')[0] === 'cards') { + return Promise.resolve({ + url: 'getCards', + status: statusCards, + json: () => Promise.resolve(fetchCards), + }); + } + else { + return Promise.resolve({ + url: 'endpoint', + status: 200, + json: () => Promise.resolve([]), + }); + } + + }); + fetchUtil.fetchWithTimeout = mockFetch; + fetchUtil.fetchWithCustomTimeout = mockFetch; +}); + +afterEach(() => { + fetchUtil.fetchWithTimeout = realFetchWithTimeout; + fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout; +}); + +test('conversation', async() => { + + render(); + + await waitFor(async () => { + expect(cardContext).not.toBe(null); + expect(channelContext).not.toBe(null); + expect(conversationContext).not.toBe(null); + }); + + await act(async () => { + cardContext.actions.setToken('abc123'); + channelContext.actions.setToken('abc123'); + }); + + 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' }, + } + }, + ]; + + await act(async () => { + cardContext.actions.setRevision(1); + channelContext.actions.setRevision(1); + }); + + act(() => { + cardContext.actions.clearToken(); + channelContext.actions.clearToken(); + }); + +}); +