testing refactored card context from mobile app

This commit is contained in:
Roland Osborne 2023-02-07 15:27:58 -08:00
parent 204f7820d4
commit 130e9f276c
2 changed files with 199 additions and 6 deletions

View File

@ -143,16 +143,26 @@ export function useCardContext() {
for (let card of delta) { for (let card of delta) {
if (card.data) { if (card.data) {
const item = setCardItem(card); const item = setCardItem(card);
const entry = cards.current.get(card.id) || { card: {}, channels: new Map() }; const entry = cards.current.get(card.id) || { card: { cardId: card.id }, channels: new Map() };
const { profileRevision, detailRevision } = entry.card; const { profileRevision, detailRevision } = entry.card;
if (item.profileRevision !== profileRevision) { 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; entry.card.profileRevision = item.profileRevision;
entry.card.profile = await getCardProfile(server, token, card.id);
await store.actions.setCardItemProfile(guid, card.id, entry.card.profileRevision, entry.card.profile); await store.actions.setCardItemProfile(guid, card.id, entry.card.profileRevision, entry.card.profile);
} }
if (item.detailRevision !== detailRevision) { 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; entry.card.detailRevision = item.detailRevision;
entry.card.detail = await getCardDetail(server, token, card.id);
await store.actions.setCardItemDetail(guid, card.id, entry.card.detailRevision, entry.card.detail); await store.actions.setCardItemDetail(guid, card.id, entry.card.detailRevision, entry.card.detail);
} }
if (entry.card.detail?.state === 'connected' && !entry.card.offsync) { if (entry.card.detail?.state === 'connected' && !entry.card.offsync) {
@ -427,7 +437,6 @@ export function useCardContext() {
const { detail, profile } = cards.current.get(cardId) || {}; const { detail, profile } = cards.current.get(cardId) || {};
return await addFlag(profile?.node, profile?.guid, channelId, topicId); return await addFlag(profile?.node, profile?.guid, channelId, topicId);
}, },
getChannelNotifications: async (cardId, channelId) => { getChannelNotifications: async (cardId, channelId) => {
const { detail, profile } = cards.current.get(cardId) || {}; const { detail, profile } = cards.current.get(cardId) || {};
const token = `${profile?.guid}.${detail?.token}`; const token = `${profile?.guid}.${detail?.token}`;
@ -438,7 +447,6 @@ export function useCardContext() {
const token = `${profile?.guid}.${detail?.token}`; const token = `${profile?.guid}.${detail?.token}`;
return await setContactChannelNotifications(profile?.node, token, channelId, notify); return await setContactChannelNotifications(profile?.node, token, channelId, notify);
}, },
getTopicItems: async (cardId, channelId) => { getTopicItems: async (cardId, channelId) => {
const { guid } = access.current; const { guid } = access.current;
return await store.actions.getCardChannelTopicItems(guid, cardId, channelId); return await store.actions.getCardChannelTopicItems(guid, cardId, channelId);
@ -455,7 +463,6 @@ export function useCardContext() {
const { guid } = access.current; const { guid } = access.current;
return await store.actions.clearCardChannelTopicItems(guid, cardId, channelId); return await store.actions.clearCardChannelTopicItems(guid, cardId, channelId);
}, },
setUnsealedChannelSubject: async (cardId, channelId, revision, unsealed) => { setUnsealedChannelSubject: async (cardId, channelId, revision, unsealed) => {
const { guid } = access.current; const { guid } = access.current;
await store.actions.setCardChannelItemUnsealedDetail(guid, cardId, channelId, revision, unsealed); await store.actions.setCardChannelItemUnsealedDetail(guid, cardId, channelId, revision, unsealed);

View File

@ -0,0 +1,186 @@
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 { CardContextProvider, CardContext } from 'context/CardContext';
import * as fetchUtil from 'api/fetchUtil';
function CardView() {
const [renderCount, setRenderCount] = useState(0);
const card = useContext(CardContext);
const [cards, setCards] = useState([]);
useEffect(() => {
setRenderCount(renderCount + 1);
const rendered = [];
card.state.cards.forEach((value) => {
rendered.push(<Text key={value.card.cardId} testID={value.card.cardId}>{ value.card.profile.handle }</Text>);
});
setCards(rendered);
}, [card.state]);
return (
<View key="cards" testID="card" card={card} renderCount={renderCount}>
{ cards }
</View>
);
}
function CardTestApp() {
return (
<CardContextProvider>
<CardView />
</CardContextProvider>
)
}
const realUseContext = React.useContext;
const realFetchWithTimeout = fetchUtil.fetchWithTimeout;
const realFetchWithCustomTimeout = fetchUtil.fetchWithCustomTimeout;
let fetchCards;
let fetchDetail;
let fetchProfile;
beforeEach(() => {
fetchCards = [];
const mockUseContext = jest.fn().mockImplementation((ctx) => {
return useTestStoreContext();
});
React.useContext = mockUseContext;
const mockFetch = jest.fn().mockImplementation((url, options) => {
console.log(url);
if (url.startsWith('https://test.org/contact/cards?agent')) {
return Promise.resolve({
json: () => Promise.resolve(fetchCards)
});
}
if (url.startsWith('https://test.org/contact/cards/000a/profile?agent')) {
return Promise.resolve({
json: () => Promise.resolve(fetchProfile)
});
}
if (url.startsWith('https://test.org/contact/cards/000a/detail?agent')) {
return Promise.resolve({
json: () => Promise.resolve(fetchDetail)
});
}
else {
return Promise.resolve({
json: () => Promise.resolve([])
});
}
});
fetchUtil.fetchWithTimeout = mockFetch;
fetchUtil.fetchWithCustomTimeout = mockFetch;
});
afterEach(() => {
React.useContext = realUseContext;
fetchUtil.fetchWithTimeout = realFetchWithTimeout;
fetchUtil.fetchWithCustomTimeout = realFetchWithCustomTimeout;
});
test('add, update, and remove', async () => {
render(<CardTestApp />)
await act(async () => {
const card = screen.getByTestId('card').props.card;
await card.actions.setSession({ guid: 'abc', server: 'test.org', token: '123' });
await card.actions.setRevision(1);
});
await waitFor(async () => {
expect(screen.getByTestId('card').props.children).toHaveLength(0);
});
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' },
},
}];
await act(async () => {
const card = screen.getByTestId('card').props.card;
await card.actions.setRevision(2);
});
await waitFor(async () => {
expect(screen.getByTestId('card').props.children).toHaveLength(1);
expect(screen.getByTestId('000a').props.children).toBe('test1');
});
fetchCards = [{
id: '000a',
revision: 2,
data: {
detailRevision: 3,
profileRevision: 4,
notifiedProfile: 3,
notifiedArticle: 5,
notifiedChannel: 6,
notifiedView: 7,
},
}];
fetchProfile = {
guid: '01ab23',
handle: 'test2',
};
fetchDetail = {
status: 'confirmed',
}
await act(async () => {
const card = screen.getByTestId('card').props.card;
await card.actions.setRevision(3);
});
await waitFor(async () => {
expect(screen.getByTestId('card').props.children).toHaveLength(1);
expect(screen.getByTestId('000a').props.children).toBe('test2');
});
fetchCards = [{
id: '000a',
revision: 3,
}];
await act(async () => {
const card = screen.getByTestId('card').props.card;
await card.actions.setRevision(3);
});
await waitFor(async () => {
expect(screen.getByTestId('card').props.children).toHaveLength(1);
});
await act(async () => {
const card = screen.getByTestId('card').props.card;
await card.actions.setRevision(4);
});
await waitFor(async () => {
expect(screen.getByTestId('card').props.children).toHaveLength(0);
});
});