UNPKG

stream-chat-react-native-core

Version:

The official React Native and Expo components for Stream Chat, a service for building chat applications

261 lines (198 loc) 9.02 kB
import { act, renderHook } from '@testing-library/react-native'; import type { Channel } from 'stream-chat'; import { generateChannelResponse } from '../../mock-builders/generator/channel'; import { getTestClientWithUser } from '../../mock-builders/mock'; import type { File } from '../../types/types'; import { EditChannelDetailsStore, useAreChannelDetailsEdited, useIsImageEdited, useIsNameEdited, } from '../edit-channel-details-store'; const file: File = { name: 'pic.png', size: 1234, type: 'image/png', uri: 'file://pic.png', }; const createChannel = async (data: { image?: string; name?: string } = {}) => { const client = await getTestClientWithUser({ id: 'me' }); const response = generateChannelResponse({ channel: data }); return client.channel('messaging', response.channel.id, response.channel) as Channel; }; describe('EditChannelDetailsStore', () => { describe('constructor', () => { it('snapshots the initial name and image from the channel', async () => { const channel = await createChannel({ image: 'http://img/original.png', name: 'Original', }); const store = new EditChannelDetailsStore(channel); const state = store.state.getLatestValue(); expect(state.initialName).toBe('Original'); expect(state.initialImage).toBe('http://img/original.png'); expect(state.currentName).toBe('Original'); expect(state.updatedImage).toBeUndefined(); expect(state.pendingAction).toBeNull(); }); it('defaults to empty name and undefined image when channel has none', async () => { const channel = await createChannel(); const store = new EditChannelDetailsStore(channel); const state = store.state.getLatestValue(); expect(state.initialName).toBe(''); expect(state.initialImage).toBeUndefined(); expect(state.currentName).toBe(''); }); }); describe('setCurrentName', () => { it('updates currentName and leaves initialName untouched', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); store.setCurrentName('Renamed'); const state = store.state.getLatestValue(); expect(state.currentName).toBe('Renamed'); expect(state.initialName).toBe('Original'); }); }); describe('setUpdatedImage', () => { it('handles File, null and back to undefined', async () => { const channel = await createChannel(); const store = new EditChannelDetailsStore(channel); store.setUpdatedImage(file); expect(store.state.getLatestValue().updatedImage).toBe(file); store.setUpdatedImage(null); expect(store.state.getLatestValue().updatedImage).toBeNull(); store.setUpdatedImage(undefined); expect(store.state.getLatestValue().updatedImage).toBeUndefined(); }); }); describe('setPendingAction', () => { it('sets each action value and clears back to null', async () => { const channel = await createChannel(); const store = new EditChannelDetailsStore(channel); (['camera', 'library', 'reset'] as const).forEach((action) => { store.setPendingAction(action); expect(store.state.getLatestValue().pendingAction).toBe(action); }); store.setPendingAction(null); expect(store.state.getLatestValue().pendingAction).toBeNull(); }); }); describe('useIsNameEdited', () => { it('is false initially', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsNameEdited(store)); expect(result.current).toBe(false); }); it('reacts to name changes', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsNameEdited(store)); expect(result.current).toBe(false); act(() => store.setCurrentName('Renamed')); expect(result.current).toBe(true); act(() => store.setCurrentName('Original')); expect(result.current).toBe(false); }); it('treats untrimmed whitespace as edited', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsNameEdited(store)); act(() => store.setCurrentName('Original ')); expect(result.current).toBe(true); }); it('ignores image changes', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsNameEdited(store)); act(() => store.setUpdatedImage(file)); expect(result.current).toBe(false); }); }); describe('useIsImageEdited', () => { it('is false initially', async () => { const channel = await createChannel({ image: 'http://img/original.png' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsImageEdited(store)); expect(result.current).toBe(false); }); it('is edited after a new image is picked', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsImageEdited(store)); act(() => store.setUpdatedImage(file)); expect(result.current).toBe(true); }); it('ignores name changes', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsImageEdited(store)); act(() => store.setCurrentName('Renamed')); expect(result.current).toBe(false); }); describe('with an initial image', () => { it('is edited on reset and clean again when untouched', async () => { const channel = await createChannel({ image: 'http://img/original.png' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsImageEdited(store)); expect(result.current).toBe(false); act(() => store.setUpdatedImage(null)); expect(result.current).toBe(true); act(() => store.setUpdatedImage(undefined)); expect(result.current).toBe(false); }); }); describe('without an initial image', () => { it('is not edited on reset but is edited when a file is picked', async () => { const channel = await createChannel(); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useIsImageEdited(store)); act(() => store.setUpdatedImage(null)); expect(result.current).toBe(false); act(() => store.setUpdatedImage(file)); expect(result.current).toBe(true); }); }); }); describe('useAreChannelDetailsEdited', () => { it('is false initially', async () => { const channel = await createChannel({ image: 'http://img/original.png', name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useAreChannelDetailsEdited(store)); expect(result.current).toBe(false); }); it('is edited when the name changes and clean again when reverted', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useAreChannelDetailsEdited(store)); act(() => store.setCurrentName('Renamed')); expect(result.current).toBe(true); act(() => store.setCurrentName('Original')); expect(result.current).toBe(false); }); it('is edited when a new image is picked', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useAreChannelDetailsEdited(store)); act(() => store.setUpdatedImage(file)); expect(result.current).toBe(true); }); it('stays edited while either field is edited', async () => { const channel = await createChannel({ name: 'Original' }); const store = new EditChannelDetailsStore(channel); const { result } = renderHook(() => useAreChannelDetailsEdited(store)); act(() => { store.setCurrentName('Renamed'); store.setUpdatedImage(file); }); expect(result.current).toBe(true); // Revert the name; image is still edited, so the form stays edited. act(() => store.setCurrentName('Original')); expect(result.current).toBe(true); // Revert the image too; now the form is clean. act(() => store.setUpdatedImage(undefined)); expect(result.current).toBe(false); }); }); });