54 lines
3.5 KiB
JavaScript
54 lines
3.5 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { createRequire } from 'node:module';
|
|
import { test } from 'node:test';
|
|
import React from 'react';
|
|
import { act, create } from 'react-test-renderer';
|
|
import ts from 'typescript';
|
|
import * as chatModel from '../src/lib/chat.ts';
|
|
|
|
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
const require = createRequire(import.meta.url);
|
|
const deferred = () => { let resolve; const promise = new Promise(yes => { resolve = yes; }); return { promise, resolve }; };
|
|
|
|
test('Eine verspätete Raumliste verdrängt keinen gerade angelegten Projektchat', async () => {
|
|
const project = { key: 'project_42', name: 'Projekt', source: 'internal', type: 'project', exists: false, projectId: 42 };
|
|
const directory = { rooms: [{ key: 'allgemein', name: 'Allgemein', source: 'internal', exists: true }, project], hiddenRoomKeys: [], invitations: [], projects: [] };
|
|
const provision = deferred(), list = deferred(), timers = new Map();
|
|
let directoryCalls = 0;
|
|
const api = { directory: () => ++directoryCalls === 1 ? Promise.resolve(directory) : list.promise, provision: () => provision.promise };
|
|
const output = ts.transpileModule(readFileSync(new URL('../app/(tabs)/communication.tsx', import.meta.url), 'utf8'), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX, target: ts.ScriptTarget.ES2022 },
|
|
}).outputText;
|
|
const exports = {};
|
|
new Function('require', 'exports', 'setInterval', 'clearInterval', output)(name => {
|
|
if (name === 'react-native') return {
|
|
...Object.fromEntries(['ActivityIndicator', 'FlatList', 'KeyboardAvoidingView', 'Modal', 'Pressable', 'ScrollView', 'Text', 'TextInput', 'View'].map(key => [key, key])),
|
|
StyleSheet: { create: value => value }, Platform: { OS: 'ios' }, DeviceEventEmitter: { emit() {} },
|
|
AppState: { currentState: 'active', addEventListener: () => ({ remove() {} }) },
|
|
};
|
|
if (name === '@expo/vector-icons') return { Ionicons: 'Icon' };
|
|
if (name === '@react-navigation/native') return { useIsFocused: () => true };
|
|
if (name === 'expo-crypto') return { randomUUID: () => 'draft-id' };
|
|
if (name === '@/components/chat-conversation') return { ChatConversation: 'Conversation' };
|
|
if (name === '@/src/lib/api') return {};
|
|
if (name === '@/src/lib/chat-api') return { chatApi: api };
|
|
if (name === '@/src/lib/chat') return chatModel;
|
|
if (name === '@/src/lib/server-config') return { getApiBaseUrlSync: () => 'https://test.invalid' };
|
|
if (name === '@/src/providers/auth-provider') return { useAuth: () => ({ token: 'test', activeTenantId: 1 }) };
|
|
return require(name);
|
|
}, exports, callback => { const id = Symbol(); timers.set(id, callback); return id; }, id => timers.delete(id));
|
|
let root;
|
|
try {
|
|
await act(async () => { root = create(React.createElement(exports.default)); });
|
|
const roomList = root.root.findAllByType('FlatList').find(node => node.props.horizontal);
|
|
await act(async () => roomList.props.renderItem({ item: project }).props.onPress());
|
|
await act(async () => { for (const callback of timers.values()) callback(); });
|
|
assert.equal(directoryCalls, 2);
|
|
await act(async () => provision.resolve({ ...project, exists: true }));
|
|
assert.equal(root.root.findByType('Conversation').props.room.key, 'project_42');
|
|
await act(async () => list.resolve(directory));
|
|
assert.equal(root.root.findByType('Conversation').props.room.key, 'project_42');
|
|
} finally { await act(async () => root?.unmount()); }
|
|
});
|