* Initial setup for new keyboard * fix the offset calculation onMove by adding isKeyboardFullyOpened * Done with the keyboard handling implementation * Handled keyboard focus and blured state using context * Added default height for input container * Android support * Tablet state handling * Fix for refreshing offset in list * Created a default context for mention post list * Fix linter errors * Fix tests * Minor * Fix the height issue for tablet view * Review comments * Dependency fix * Reveiw comment * keyboard animation only enabled with screen on top navigation * added tests * Added extra keyboard component for emoji picker (#9328) * Added extra keyboard component * handled swipe geature for extra keyboard * scroll to bottom visible on emoji picker * Check for stale event for keyboard geature area * fix keyboard stale event for mid-gesture change swipe direction * Closing emoji picker when message priority is opened * changing to thread view closes emoji picker * Close emoij picker and keyboard when attachment icons are clicked * handle android emoji picker behaviour * Remove emoji picker code * fix tests * Address reviev comments * Test fixes * usePreventDoubleTab for race condition and corrected comment on isInputAccessoryViewMode flag * File attachments option in bottom sheet quick action (#9331) * Added extra keyboard component * handled swipe geature for extra keyboard * File attachments option in bottom sheet quick action * Updated tests * i18n * fix test * Added tests * Review comment * fix tests * Integrated Emoji picker to Extra keyboard component. (#9339) * Added extra keyboard component * handled swipe geature for extra keyboard * scroll to bottom visible on emoji picker * Fix the post input container height change issue * Added emoji picker with search functionality * keyboard height not recorded fallback to default height, set search to false closing emoji picker * fix search funcitonality in android * scroll to end bottom dismissed with pressed * Fixed the scroll issue for android * fix the flickering post input issue * Wired up the emoji picker * Added keyboard and spaceback in emoji picker * intl extract * initial cursor position and simple calculation review comment * separated grapheme to utils file * Review comments * nitpick * Fix the bottom safe area and navigation stack restore fix * Fix test * disabled emoji picker in edit post screen * change the name of the variable to name it clarier * fix the tab gap issue in andriod * disabled the emoji skin tone change on andriod * fix the input container jump issue * fix the failing test * UX review * added white space after the attachment icon * When @ or / is press open keyboard on andriod also fix the scroll issue when keyboard is open * back bottom closes emoji picker and opening keyboard jump fix * reverted code * fixed the flickering issue of input and scroll position fix * Added BoR button * Fix the gap issue in thread * fix the warning reaminated issue when opening a channel * Fix the extra space issue between input and emoij picker * Minor fix for extra space between input and emoji picker * WIP * Fix thread view bottom safe area and gap between keyboard and searched emojis * WIP * refactor: make borConfig optional in BoRAction component * refactor: remove optional borConfig and simplify state initialization * Fix the keyboard issue in tablet * Fix the warning issue react-native-keyboard-controller * Fix tests * Fix the tablet search hight issue * Replaced the ExtraKeyboardProvider with KeyboardProvider from rnkc for permalink * WIP * Successfully toggeled bor status * Displayed bor chip in draft editor * Send bor post * Displayed bor chip in draft editor with wrapping * Added read receipt * Bottom sheet jump issue resolved * Search do not close after selecting emoji in search list * Added the bottom inset height in search emoji for android * integrated bor receipt count * fix buid issue * Added margin * Handled updating receipts on sync * test: add comprehensive tests for updateDraftBoRConfig * test: add initial test file for burn on read label component * test: add tests for BoRLabel component * test: update BoRLabel tests to use toBeVisible and remove formatTime mock * test: update BoR label tests to use renderWithIntl * refactor: remove getBaseProps and specify props inline in BoRLabel tests * refactor: improve test component formatting for readability * test: add validation for BoRLabel time display formats * test: add comprehensive tests for Burst on Read (BoR) functionality * WIP * test: add unit tests for BOR quick action component * test: add comprehensive tests for BoR quick action component * test: add missing props to QuickActions test setup * test: add tests for BoR quick action rendering * test: mock BoRQuickAction component for testing * test: add comprehensive tests for observeIsBoREnabled function * test: add initial test file for BOR read receipts screen * test: add comprehensive tests for BORReadReceipts component * test: add test cases for BOR read receipts display * test: add comprehensive tests for humanReadable format in formatTime * Added tests * lint fix * cleanup * cleanup * cleanup * cleanup * cleanup * i18n fix * Fix the cancel state to emoji picker * Prevented displaying BoR quick action in threads * Fixed a test * lint fix * review fixes * review fixes * i18n fix * fixed tests * review fixes * lint fix * restored podfile * Fixed WS event handling for receiving bor post receipnt * Fixed a test * fixed TS * Implemented burn post now for sender and receiver (#9401) * Implemented burn post now for sender and receiver * test: add tests for burnPostNow function * test: add test for delete post option * test: add comprehensive tests for DeletePostOption component * Added tests * Lint fix * minor improvemenmts * lint fix * reset unintended changes * reset unintended changes * Bor delete when read by all (#9407) * WIP * Updated for all read * cleanup * test: add comprehensive tests for handleBoRPostAllRevealed * test: add tests for BOR events in websocket event handler * feat: add comprehensive tests for shouldUpdateForBoRPost function * Added tests * Lint fix * fixed TS * fixed padding * UX fixes --------- Co-authored-by: Rajat Dabade <a-rajat.dabade@mattermost.com> Co-authored-by: Rajat Dabade <rajatdabade1997@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: Rahim Rahman <rahim.rahman@mattermost.com>
453 lines
18 KiB
TypeScript
453 lines
18 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {DeviceEventEmitter} from 'react-native';
|
|
|
|
import {Navigation, Screens} from '@constants';
|
|
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
|
import {DRAFT_SCREEN_TAB_DRAFTS, DRAFT_SCREEN_TAB_SCHEDULED_POSTS} from '@constants/draft';
|
|
import {PostTypes} from '@constants/post';
|
|
import DatabaseManager from '@database/manager';
|
|
import {goToScreen, popTo} from '@screens/navigation';
|
|
import NavigationStore from '@store/navigation_store';
|
|
import {isTablet} from '@utils/helpers';
|
|
|
|
import {
|
|
switchToGlobalDrafts,
|
|
updateDraftFile,
|
|
removeDraftFile,
|
|
updateDraftMessage,
|
|
addFilesToDraft,
|
|
removeDraft,
|
|
updateDraftPriority,
|
|
updateDraftBoRConfig,
|
|
updateDraftMarkdownImageMetadata,
|
|
} from './draft';
|
|
|
|
import type ServerDataOperator from '@database/operator/server_data_operator';
|
|
import type DraftModel from '@typings/database/models/servers/draft';
|
|
|
|
let operator: ServerDataOperator;
|
|
const serverUrl = 'baseHandler.test.com';
|
|
const channelId = 'id1';
|
|
const teamId = 'tId1';
|
|
const channel: Channel = {
|
|
id: channelId,
|
|
team_id: teamId,
|
|
total_msg_count: 0,
|
|
} as Channel;
|
|
const fileInfo: FileInfo = {
|
|
id: 'fileid',
|
|
clientId: 'clientid',
|
|
localPath: 'path1',
|
|
} as FileInfo;
|
|
const draft: Draft = {
|
|
channel_id: channel.id,
|
|
message: 'test',
|
|
root_id: '',
|
|
update_at: Date.now(),
|
|
} as Draft;
|
|
|
|
beforeEach(async () => {
|
|
await DatabaseManager.init([serverUrl]);
|
|
operator = DatabaseManager.serverDatabases[serverUrl]!.operator;
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await DatabaseManager.destroyServerDatabase(serverUrl);
|
|
});
|
|
|
|
jest.mock('@utils/helpers', () => ({
|
|
...jest.requireActual('@utils/helpers'),
|
|
isTablet: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('@screens/navigation', () => ({
|
|
popTo: jest.fn(),
|
|
goToScreen: jest.fn(),
|
|
}));
|
|
|
|
describe('updateDraftFile', () => {
|
|
it('handle not found database', async () => {
|
|
const {error} = await updateDraftFile('foo', channelId, '', fileInfo, false);
|
|
expect(error).toBeTruthy();
|
|
});
|
|
|
|
it('handle no draft', async () => {
|
|
const {error} = await updateDraftFile(serverUrl, channelId, '', fileInfo, false);
|
|
expect(error).toBeTruthy();
|
|
expect(error).toBe('no draft');
|
|
});
|
|
|
|
it('handle no file', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
|
|
const {error} = await updateDraftFile(serverUrl, channelId, '', fileInfo, false);
|
|
expect(error).toBeTruthy();
|
|
expect(error).toBe('file not found');
|
|
});
|
|
|
|
it('update draft file', async () => {
|
|
await operator.handleDraft({drafts: [{...draft, files: [{...fileInfo, localPath: 'path0'}]}], prepareRecordsOnly: false});
|
|
|
|
const {draft: draftModel, error} = await updateDraftFile(serverUrl, channelId, '', fileInfo);
|
|
expect(error).toBeUndefined();
|
|
expect(draftModel).toBeDefined();
|
|
expect(draftModel?.files?.length).toBe(1);
|
|
expect(draftModel?.files![0].localPath).toBe('path1');
|
|
});
|
|
});
|
|
|
|
describe('removeDraftFile', () => {
|
|
it('handle not found database', async () => {
|
|
const {error} = await removeDraftFile('foo', channelId, '', '', false);
|
|
expect(error).toBeTruthy();
|
|
});
|
|
|
|
it('handle no draft', async () => {
|
|
const {error} = await removeDraftFile(serverUrl, channelId, '', 'clientid', false);
|
|
expect(error).toBeTruthy();
|
|
expect(error).toBe('no draft');
|
|
});
|
|
|
|
it('handle no file', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
|
|
const {error} = await removeDraftFile(serverUrl, channelId, '', 'clientid', false);
|
|
expect(error).toBeTruthy();
|
|
expect(error).toBe('file not found');
|
|
});
|
|
|
|
it('remove draft file', async () => {
|
|
await operator.handleDraft({drafts: [{...draft, files: [fileInfo]}], prepareRecordsOnly: false});
|
|
|
|
const {draft: draftModel, error} = await removeDraftFile(serverUrl, channelId, '', 'clientid');
|
|
expect(error).toBeUndefined();
|
|
expect(draftModel).toBeDefined();
|
|
});
|
|
|
|
it('remove draft file, no message', async () => {
|
|
await operator.handleDraft({drafts: [{channel_id: channel.id, files: [fileInfo], root_id: '', update_at: Date.now()}], prepareRecordsOnly: false});
|
|
|
|
const {draft: draftModel, error} = await removeDraftFile(serverUrl, channelId, '', 'clientid', false);
|
|
expect(error).toBeUndefined();
|
|
expect(draftModel).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('updateDraftMessage', () => {
|
|
it('handle not found database', async () => {
|
|
const result = await updateDraftMessage('foo', channelId, '', 'newmessage', false) as {draft: unknown; error: unknown};
|
|
expect(result.error).toBeDefined();
|
|
expect(result.draft).toBeUndefined();
|
|
});
|
|
|
|
it('update draft message, blank message, no draft', async () => {
|
|
const result = await updateDraftMessage(serverUrl, channelId, '', '', false) as {draft: unknown; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeUndefined();
|
|
});
|
|
|
|
it('update draft message, no draft', async () => {
|
|
const models = await updateDraftMessage(serverUrl, channelId, '', 'newmessage', false) as DraftModel[];
|
|
expect(models).toBeDefined();
|
|
expect(models?.length).toBe(1);
|
|
});
|
|
|
|
it('update draft message', async () => {
|
|
await operator.handleDraft({drafts: [{...draft, files: [fileInfo]}], prepareRecordsOnly: false});
|
|
|
|
const result = await updateDraftMessage(serverUrl, channelId, '', 'newmessage') as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result.draft.message).toBe('newmessage');
|
|
});
|
|
|
|
it('update draft message, same message', async () => {
|
|
await operator.handleDraft({drafts: [{...draft, files: [fileInfo]}], prepareRecordsOnly: false});
|
|
|
|
const result = await updateDraftMessage(serverUrl, channelId, '', 'test', false) as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result.draft.message).toBe('test');
|
|
});
|
|
|
|
it('update draft message, no file', async () => {
|
|
await operator.handleDraft({drafts: [{channel_id: channel.id, files: [], root_id: '', update_at: Date.now()}], prepareRecordsOnly: false});
|
|
|
|
const result = await updateDraftMessage(serverUrl, channelId, '', 'newmessage', false) as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result.draft.message).toBe('newmessage');
|
|
});
|
|
});
|
|
|
|
describe('addFilesToDraft', () => {
|
|
it('handle not found database', async () => {
|
|
const result = await addFilesToDraft('foo', channelId, '', [], false) as {draft: unknown; error: unknown};
|
|
expect(result.error).toBeDefined();
|
|
expect(result.draft).toBeUndefined();
|
|
});
|
|
|
|
it('add draft files, no draft', async () => {
|
|
const models = await addFilesToDraft(serverUrl, channelId, '', [fileInfo], false) as DraftModel[];
|
|
expect(models).toBeDefined();
|
|
expect(models?.length).toBe(1);
|
|
});
|
|
|
|
it('add draft files', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
|
|
const result = await addFilesToDraft(serverUrl, channelId, '', [fileInfo]) as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result?.draft.files.length).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('removeDraft', () => {
|
|
it('handle not found database', async () => {
|
|
const result = await removeDraft('foo', channelId, '');
|
|
expect(result.error).toBeDefined();
|
|
expect(result.draft).toBeUndefined();
|
|
});
|
|
|
|
it('handle no draft', async () => {
|
|
const result = await removeDraft(serverUrl, channelId, '');
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeUndefined();
|
|
});
|
|
|
|
it('remove draft', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
|
|
const result = await removeDraft(serverUrl, channelId);
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
});
|
|
|
|
it('remove draft with root id', async () => {
|
|
await operator.handleDraft({drafts: [{...draft, root_id: 'postid'}], prepareRecordsOnly: false});
|
|
|
|
const result = await removeDraft(serverUrl, channelId, 'postid');
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('updateDraftPriority', () => {
|
|
const postPriority: PostPriority = {
|
|
priority: 'urgent',
|
|
} as PostPriority;
|
|
|
|
it('handle not found database', async () => {
|
|
const result = await updateDraftPriority('foo', channelId, '', postPriority) as {draft: unknown; error: unknown};
|
|
expect(result.error).toBeDefined();
|
|
expect(result.draft).toBeUndefined();
|
|
});
|
|
|
|
it('handle no draft', async () => {
|
|
const models = await updateDraftPriority(serverUrl, channelId, '', postPriority) as DraftModel[];
|
|
expect(models).toBeDefined();
|
|
expect(models.length).toBe(1);
|
|
expect(models[0].metadata?.priority?.priority).toBe(postPriority.priority);
|
|
});
|
|
|
|
it('update draft priority', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
|
|
const result = await updateDraftPriority(serverUrl, channelId, '', postPriority) as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result.draft.metadata?.priority?.priority).toBe(postPriority.priority);
|
|
});
|
|
});
|
|
|
|
describe('switchToGlobalDrafts', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
it('should emit navigation event on tablet', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(true);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
|
|
await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID, value: teamId}], prepareRecordsOnly: false});
|
|
|
|
await switchToGlobalDrafts(serverUrl);
|
|
|
|
expect(emitSpy).toHaveBeenCalledWith(Navigation.NAVIGATION_HOME, Screens.GLOBAL_DRAFTS, {});
|
|
});
|
|
|
|
it('if prepareRecordsOnly is true, should emit navigation event on tablet for Scheduled post tab and also call batchRecord', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(true);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
const batchRecordSpy = jest.spyOn(operator, 'batchRecords');
|
|
|
|
await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID, value: teamId}], prepareRecordsOnly: false});
|
|
|
|
await switchToGlobalDrafts(serverUrl, '', DRAFT_SCREEN_TAB_SCHEDULED_POSTS, true);
|
|
|
|
expect(batchRecordSpy).toHaveBeenCalled();
|
|
expect(emitSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should fail to emit navigation event on tablet', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(true);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
|
|
await switchToGlobalDrafts('nonexistent');
|
|
|
|
expect(emitSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should fail to emit navigation event on tablet if currentTeamId is not set', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(true);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
|
|
await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID, value: ''}], prepareRecordsOnly: false});
|
|
|
|
await switchToGlobalDrafts(serverUrl);
|
|
|
|
expect(emitSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call goToScreen on non-tablet', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(false);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
|
|
const goToScreenMock = jest.mocked(goToScreen);
|
|
|
|
await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID, value: teamId}], prepareRecordsOnly: false});
|
|
await switchToGlobalDrafts(serverUrl);
|
|
|
|
expect(goToScreenMock).toHaveBeenCalledWith(Screens.GLOBAL_DRAFTS, '', {}, {topBar: {visible: false}});
|
|
expect(emitSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not call goToScreen on non-tablet when server url is a non existent URL', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(false);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
const goToScreenMock = jest.mocked(goToScreen);
|
|
|
|
await switchToGlobalDrafts('nonexistent');
|
|
|
|
expect(goToScreenMock).not.toHaveBeenCalled();
|
|
expect(emitSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should pass initialTab param when provided', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(true);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
|
|
await switchToGlobalDrafts(serverUrl, teamId, DRAFT_SCREEN_TAB_SCHEDULED_POSTS);
|
|
expect(emitSpy).toHaveBeenCalledWith(Navigation.NAVIGATION_HOME, Screens.GLOBAL_DRAFTS, {initialTab: DRAFT_SCREEN_TAB_SCHEDULED_POSTS});
|
|
|
|
await switchToGlobalDrafts(serverUrl, teamId, DRAFT_SCREEN_TAB_DRAFTS);
|
|
expect(emitSpy).toHaveBeenCalledWith(Navigation.NAVIGATION_HOME, Screens.GLOBAL_DRAFTS, {initialTab: DRAFT_SCREEN_TAB_DRAFTS});
|
|
});
|
|
|
|
it('should pass initialTab param when provided on non-tablet', async () => {
|
|
jest.mocked(isTablet).mockReturnValue(false);
|
|
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
|
|
const goToScreenMock = jest.mocked(goToScreen);
|
|
|
|
await switchToGlobalDrafts(serverUrl, teamId, DRAFT_SCREEN_TAB_SCHEDULED_POSTS);
|
|
expect(goToScreenMock).toHaveBeenCalledWith(Screens.GLOBAL_DRAFTS, '', {initialTab: DRAFT_SCREEN_TAB_SCHEDULED_POSTS}, {topBar: {visible: false}});
|
|
|
|
await switchToGlobalDrafts(serverUrl, teamId, DRAFT_SCREEN_TAB_DRAFTS);
|
|
expect(goToScreenMock).toHaveBeenCalledWith(Screens.GLOBAL_DRAFTS, '', {initialTab: DRAFT_SCREEN_TAB_DRAFTS}, {topBar: {visible: false}});
|
|
expect(emitSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call popto from navigation store if Global draft is alreay present', async () => {
|
|
NavigationStore.addScreenToStack(Screens.GLOBAL_DRAFTS);
|
|
NavigationStore.addScreenToStack(Screens.CHANNEL);
|
|
NavigationStore.addScreenToStack(Screens.THREAD);
|
|
|
|
await switchToGlobalDrafts(serverUrl, teamId, DRAFT_SCREEN_TAB_SCHEDULED_POSTS);
|
|
|
|
expect(popTo).toHaveBeenCalledWith(Screens.GLOBAL_DRAFTS);
|
|
});
|
|
});
|
|
|
|
describe('updateDraftMarkdownImageMetadata', () => {
|
|
const postImageData: PostImage = {
|
|
height: 1080,
|
|
width: 1920,
|
|
format: 'jpg',
|
|
frame_count: undefined,
|
|
};
|
|
|
|
it('handle not found database', async () => {
|
|
const result = await updateDraftMarkdownImageMetadata({
|
|
serverUrl: 'foo',
|
|
channelId,
|
|
rootId: '',
|
|
imageMetadata: {
|
|
image1: postImageData,
|
|
},
|
|
}) as {draft: unknown; error: unknown};
|
|
expect(result.error).toBeDefined();
|
|
expect(result.draft).toBeUndefined();
|
|
});
|
|
|
|
it('handle update image metadata', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
const result = await updateDraftMarkdownImageMetadata({
|
|
serverUrl,
|
|
channelId,
|
|
rootId: '',
|
|
imageMetadata: {
|
|
image1: postImageData,
|
|
},
|
|
}) as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result.draft.metadata?.images?.image1).toEqual(postImageData);
|
|
});
|
|
});
|
|
|
|
describe('updateDraftBoRConfig', () => {
|
|
const postBoRConfig: PostBoRConfig = {
|
|
enabled: true,
|
|
borDurationSeconds: 300,
|
|
borMaximumTimeToLiveSeconds: 3600,
|
|
};
|
|
|
|
it('handle not found database', async () => {
|
|
const result = await updateDraftBoRConfig('foo', channelId, '', postBoRConfig) as {draft: unknown; error: unknown};
|
|
expect(result.error).toBeTruthy();
|
|
});
|
|
|
|
it('handle no draft', async () => {
|
|
const models = await updateDraftBoRConfig(serverUrl, channelId, '', postBoRConfig) as DraftModel[];
|
|
expect(models).toBeDefined();
|
|
expect(models.length).toBe(1);
|
|
expect(models[0].metadata?.borConfig?.enabled).toBe(postBoRConfig.enabled);
|
|
expect(models[0].metadata?.borConfig?.borDurationSeconds).toBe(postBoRConfig.borDurationSeconds);
|
|
expect(models[0].type).toBe(PostTypes.BURN_ON_READ);
|
|
});
|
|
|
|
it('update draft BoR config with enabled true', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
|
|
const result = await updateDraftBoRConfig(serverUrl, channelId, '', postBoRConfig) as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result.draft.metadata?.borConfig?.enabled).toBe(postBoRConfig.enabled);
|
|
expect(result.draft.metadata?.borConfig?.borDurationSeconds).toBe(postBoRConfig.borDurationSeconds);
|
|
expect(result.draft.type).toBe('burn_on_read');
|
|
});
|
|
|
|
it('update draft BoR config with enabled false', async () => {
|
|
await operator.handleDraft({drafts: [draft], prepareRecordsOnly: false});
|
|
|
|
const disabledBoRConfig = {...postBoRConfig, enabled: false};
|
|
const result = await updateDraftBoRConfig(serverUrl, channelId, '', disabledBoRConfig) as {draft: DraftModel; error: unknown};
|
|
expect(result.error).toBeUndefined();
|
|
expect(result.draft).toBeDefined();
|
|
expect(result.draft.metadata?.borConfig?.enabled).toBe(false);
|
|
expect(result.draft.type).toBe('');
|
|
});
|
|
});
|