databag/net/web/test/Conversation.test.tsx

584 lines
13 KiB
TypeScript
Raw Normal View History

import React, { useState, useEffect, useContext } from 'react';
2024-04-25 20:29:25 +00:00
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(() => {
2024-04-25 20:29:25 +00:00
const rendered = [];
const entries = Array.from(conversation.state.topics.values());
2024-04-25 20:29:25 +00:00
entries.forEach((entry) => {
rendered.push(
2024-04-25 20:29:25 +00:00
<div
key={entry.id}
data-testid="topic"
>
2023-01-10 23:35:57 +00:00
<span data-testid="data">{entry.data.topicDetail.data}</span>
2024-04-25 20:29:25 +00:00
</div>,
);
});
setTopics(rendered);
setRenderCount(renderCount + 1);
2024-04-25 20:29:25 +00:00
}, [conversation.state]);
return (
//@ts-ignore
2024-04-25 20:29:25 +00:00
<div
data-testid="topics"
count={renderCount}
offsync={card.state.offsync.toString()}
>
{topics}
</div>
);
}
function ConversationTestApp() {
return (
<CardContextProvider>
<ChannelContextProvider>
<ConversationContextProvider>
<ConversationView />
</ConversationContextProvider>
</ChannelContextProvider>
</CardContextProvider>
2024-04-25 20:29:25 +00:00
);
}
const realFetchWithTimeout = fetchUtil.fetchWithTimeout;
const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout;
let beginSet;
2023-01-11 06:49:02 +00:00
let endSet;
let statusCards;
let fetchCards;
let statusChannels;
let fetchChannels;
let statusCardChannels;
let fetchCardChannels;
2023-01-10 23:35:57 +00:00
let statusTopics;
let fetchTopics;
2023-01-11 06:10:05 +00:00
let statusTopic;
let fetchTopic;
beforeEach(() => {
statusCards = 200;
fetchCards = [];
statusChannels = 200;
fetchChannels = [];
statusCardChannels = 200;
fetchCardChannels = [];
2023-01-10 23:35:57 +00:00
statusTopics = 200;
fetchTopics = [];
2023-01-11 06:10:05 +00:00
statusTopic = 200;
fetchTopic = {};
2023-01-11 06:49:02 +00:00
endSet = false;
beginSet = false;
const mockFetch = jest.fn().mockImplementation((url, options) => {
const params = url.split('/');
2023-01-18 07:42:22 +00:00
if (params[2]?.startsWith('channels?agent')) {
return Promise.resolve({
url: 'getChannels',
status: statusChannels,
json: () => Promise.resolve(fetchChannels),
});
2024-04-25 20:29:25 +00:00
} else if (params[4]?.startsWith('channels?contact')) {
return Promise.resolve({
url: 'getCardChannels',
status: statusCardChannels,
json: () => Promise.resolve(fetchCardChannels),
});
2024-04-25 20:29:25 +00:00
} else if (params[2]?.split('?')[0] === 'cards') {
return Promise.resolve({
url: 'getCards',
status: statusCards,
json: () => Promise.resolve(fetchCards),
});
2024-04-25 20:29:25 +00:00
} else if (params[4] === 'topics') {
2023-01-11 06:10:05 +00:00
return Promise.resolve({
url: 'getTopic',
status: statusTopic,
json: () => Promise.resolve(fetchTopic),
});
2024-04-25 20:29:25 +00:00
} else if (params[6]?.split('?')[0] === 'topics' || params[4]?.split('?')[0] === 'topics') {
2023-01-11 06:49:02 +00:00
if (url.endsWith('end=48')) {
endSet = true;
}
if (url.endsWith('begin=48')) {
beginSet = true;
}
2023-01-11 06:49:02 +00:00
const headers = new Map();
headers.set('topic-marker', 48);
headers.set('topic-revision', 55);
2023-01-10 23:35:57 +00:00
return Promise.resolve({
url: 'getTopics',
status: statusTopics,
2023-01-11 06:49:02 +00:00
headers: headers,
2023-01-10 23:35:57 +00:00
json: () => Promise.resolve(fetchTopics),
});
2024-04-25 20:29:25 +00:00
} else {
return Promise.resolve({
url: 'endpoint',
status: 200,
2023-01-10 21:16:13 +00:00
headers: new Map(),
2023-01-11 06:10:05 +00:00
json: () => Promise.resolve({}),
});
}
});
//@ts-ignore
fetchUtil.fetchWithTimeout = mockFetch;
//@ts-ignore
fetchUtil.fetchWithCustomTimeout = mockFetch;
});
afterEach(() => {
//@ts-ignore
fetchUtil.fetchWithTimeout = realFetchWithTimeout;
//@ts-ignore
fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout;
});
2024-04-25 20:29:25 +00:00
test('add, update, and remove topic', async () => {
render(<ConversationTestApp />);
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 = [
2024-04-25 20:29:25 +00:00
{
id: '123',
revision: 2,
data: {
detailRevision: 3,
topicRevision: 5,
channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testdata' },
channelDetail: { dataType: 'superbasic', data: 'testdata' },
2024-04-25 20:29:25 +00:00
},
},
];
2024-04-25 20:29:25 +00:00
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',
},
},
},
2024-04-25 20:29:25 +00:00
];
fetchCardChannels = [
2024-04-25 20:29:25 +00:00
{
id: 'aabb',
revision: 2,
data: {
detailRevision: 3,
topicRevision: 5,
channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testcardtopic' },
channelDetail: { dataType: 'superbasic', data: 'testcardchannel' },
2024-04-25 20:29:25 +00:00
},
},
];
await act(async () => {
cardContext.actions.setRevision(1);
channelContext.actions.setRevision(1);
});
2023-01-10 23:35:57 +00:00
fetchTopics = [
2024-04-25 20:29:25 +00:00
{
id: '888',
revision: 5,
data: {
detailRevision: 3,
tagRevision: 0,
topicDetail: {
guid: '0123',
dataType: 'topictype',
data: 'contacttopicdata',
created: 1,
updated: 1,
status: 'confirmed',
transform: 'complete',
},
2023-01-10 23:35:57 +00:00
},
2024-04-25 20:29:25 +00:00
},
2023-01-10 23:35:57 +00:00
];
2023-01-10 21:16:13 +00:00
await act(async () => {
conversationContext.actions.setChannel('000a', 'aabb');
});
2023-01-10 23:35:57 +00:00
await waitFor(async () => {
expect(screen.getByTestId('topics').children).toHaveLength(1);
expect(screen.getByTestId('data').textContent).toBe('contacttopicdata');
});
fetchTopics = [
2024-04-25 20:29:25 +00:00
{
id: '888',
revision: 5,
data: {
detailRevision: 3,
tagRevision: 0,
topicDetail: {
guid: '0123',
dataType: 'topictype',
data: 'agenttopicdata',
created: 1,
updated: 1,
status: 'confirmed',
transform: 'complete',
},
2023-01-10 23:35:57 +00:00
},
2024-04-25 20:29:25 +00:00
},
2023-01-10 23:35:57 +00:00
];
await act(async () => {
conversationContext.actions.setChannel(null, '123');
});
await waitFor(async () => {
expect(screen.getByTestId('topics').children).toHaveLength(1);
expect(screen.getByTestId('data').textContent).toBe('agenttopicdata');
});
2023-01-11 06:10:05 +00:00
fetchChannels = [
2024-04-25 20:29:25 +00:00
{
id: '123',
revision: 2,
data: {
2023-01-11 06:10:05 +00:00
detailRevision: 3,
topicRevision: 6,
2024-04-25 20:29:25 +00:00
},
2023-01-11 06:10:05 +00:00
},
];
fetchTopics = [
2024-04-25 20:29:25 +00:00
{
id: '888',
revision: 5,
data: {
detailRevision: 3,
tagRevision: 0,
},
},
2023-01-11 06:10:05 +00:00
];
2024-04-25 20:29:25 +00:00
fetchTopic = {
id: '888',
revision: 5,
data: {
2023-01-11 06:10:05 +00:00
detailRevision: 4,
tagRevision: 0,
topicDetail: {
guid: '0123',
dataType: 'topictype',
data: 'agenttopicdata2',
created: 1,
updated: 1,
status: 'confirmed',
transform: 'complete',
},
2024-04-25 20:29:25 +00:00
},
2023-01-11 06:10:05 +00:00
};
await act(async () => {
channelContext.actions.setRevision(2);
});
await waitFor(async () => {
expect(screen.getByTestId('topics').children).toHaveLength(1);
expect(screen.getByTestId('data').textContent).toBe('agenttopicdata');
});
fetchChannels = [
2024-04-25 20:29:25 +00:00
{
id: '123',
revision: 3,
data: {
2023-01-11 06:10:05 +00:00
detailRevision: 3,
topicRevision: 7,
2024-04-25 20:29:25 +00:00
},
2023-01-11 06:10:05 +00:00
},
];
fetchTopics = [
2024-04-25 20:29:25 +00:00
{
id: '888',
revision: 6,
data: {
detailRevision: 4,
tagRevision: 0,
},
},
2023-01-11 06:10:05 +00:00
];
await act(async () => {
channelContext.actions.setRevision(3);
});
await waitFor(async () => {
expect(screen.getByTestId('topics').children).toHaveLength(1);
expect(screen.getByTestId('data').textContent).toBe('agenttopicdata2');
});
fetchChannels = [
2024-04-25 20:29:25 +00:00
{
id: '123',
revision: 2,
data: {
2023-01-11 06:10:05 +00:00
detailRevision: 3,
topicRevision: 8,
2024-04-25 20:29:25 +00:00
},
2023-01-11 06:10:05 +00:00
},
];
2024-04-25 20:29:25 +00:00
fetchTopics = [{ id: '888', revision: 6 }];
2023-01-11 06:10:05 +00:00
await act(async () => {
channelContext.actions.setRevision(4);
});
await waitFor(async () => {
expect(screen.getByTestId('topics').children).toHaveLength(0);
});
act(() => {
cardContext.actions.clearToken();
channelContext.actions.clearToken();
});
});
2024-04-25 20:29:25 +00:00
test('load more', async () => {
2023-01-11 06:49:02 +00:00
render(<ConversationTestApp />);
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');
});
2024-04-25 20:29:25 +00:00
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',
},
},
2023-01-11 06:49:02 +00:00
},
2024-04-25 20:29:25 +00:00
];
2023-01-11 06:49:02 +00:00
fetchCardChannels = [
2024-04-25 20:29:25 +00:00
{
id: 'aabb',
revision: 2,
data: {
2023-01-11 06:49:02 +00:00
detailRevision: 3,
topicRevision: 5,
channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testcardtopic' },
channelDetail: { dataType: 'superbasic', data: 'testcardchannel' },
2024-04-25 20:29:25 +00:00
},
2023-01-11 06:49:02 +00:00
},
];
await act(async () => {
cardContext.actions.setRevision(1);
channelContext.actions.setRevision(1);
});
fetchTopics = [];
for (let i = 0; i < 32; i++) {
2024-04-25 20:29:25 +00:00
fetchTopics.push({
id: i.toString(),
revision: 5,
data: {
detailRevision: 3,
tagRevision: 0,
topicDetail: {
guid: '0123',
dataType: 'topictype',
data: 'contacttopicdata',
created: 1,
updated: 1,
status: 'confirmed',
transform: 'complete',
},
2023-01-11 06:49:02 +00:00
},
2024-04-25 20:29:25 +00:00
});
}
2023-01-11 06:49:02 +00:00
await act(async () => {
await conversationContext.actions.setChannel('000a', 'aabb');
});
await waitFor(async () => {
expect(endSet).toBe(false);
expect(beginSet).toBe(false);
2023-01-11 06:49:02 +00:00
expect(screen.getByTestId('topics').children).toHaveLength(32);
});
fetchTopics = [];
for (let i = 100; i < 111; i++) {
2024-04-25 20:29:25 +00:00
fetchTopics.push({
id: i.toString(),
revision: 5,
data: {
detailRevision: 3,
tagRevision: 0,
topicDetail: {
guid: '0123',
dataType: 'topictype',
data: 'contacttopicdata',
created: 1,
updated: 1,
status: 'confirmed',
transform: 'complete',
},
2023-01-11 06:49:02 +00:00
},
2024-04-25 20:29:25 +00:00
});
}
2023-01-11 06:49:02 +00:00
await act(async () => {
await conversationContext.actions.loadMore();
});
await waitFor(async () => {
expect(endSet).toBe(true);
expect(beginSet).toBe(false);
2023-01-11 06:49:02 +00:00
expect(screen.getByTestId('topics').children).toHaveLength(43);
});
2024-04-25 20:29:25 +00:00
fetchCards = [
{
id: '000a',
revision: 2,
data: {
detailRevision: 2,
profileRevision: 3,
notifiedProfile: 3,
notifiedArticle: 5,
notifiedChannel: 7,
notifiedView: 7,
},
},
2024-04-25 20:29:25 +00:00
];
fetchCardChannels = [
2024-04-25 20:29:25 +00:00
{
id: 'aabb',
revision: 2,
data: {
detailRevision: 3,
topicRevision: 6,
channelSummary: { guid: '11', dataType: 'superbasictopic', data: 'testcardtopic' },
channelDetail: { dataType: 'superbasic', data: 'testcardchannel' },
2024-04-25 20:29:25 +00:00
},
},
];
await act(async () => {
cardContext.actions.setRevision(2);
});
await waitFor(async () => {
expect(beginSet).toBe(true);
});
2024-04-25 20:29:25 +00:00
fetchTopics = [
{
id: 300,
revision: 5,
data: {
detailRevision: 3,
tagRevision: 0,
topicDetail: {
guid: '0123',
dataType: 'topictype',
data: 'contacttopicdata',
created: 1,
updated: 1,
status: 'confirmed',
transform: 'complete',
},
},
},
2024-04-25 20:29:25 +00:00
];
await act(async () => {
conversationContext.actions.resync();
});
await waitFor(async () => {
expect(screen.getByTestId('topics').children).toHaveLength(44);
});
2023-01-11 06:49:02 +00:00
await act(async () => {
await conversationContext.actions.clearChannel();
});
await waitFor(async () => {
expect(screen.getByTestId('topics').children).toHaveLength(0);
});
});