mattermost-mobile/app/actions/local/draft.test.ts
Mattermost Build 0f55d7e702
Mobile drafts (#8280) (#8473)
* refactor: started with draft, done until new tabs for draft

* refactor: change the query and added the screen for draft

* added condition for fetching draft for channel delete or not

* refactor: added draft screen

* linter fixes

* Added draft post component

* added avatar and header display name for the draft post list

* added channel info component

* channel info completed

* proper naming

* added image file markdown acknowledgement support

* draft actions

* Fix the draft receiver in drafts

* separated send message handler

* Done with send drafts

* done with delete drafts

* change save to send draft

* handle lengthy message with show more button

* done with persistent message edit, send and delete drafts

* added alert for sending message

* added update at time for the drafts

* en.json extract fix

* Updated dependencies for useCallback

* refactor: added drafts list to animated list

* added swipeable component and delete conformation for drafts

* done with rendering of images in markdown for drafts

* en.json issue fixed

* fix en.json issue

* refactor: en.json fix

* addressed review comments

* updated image metadata handling code

* linter fixes

* added the empty draft screen

* linter fix

* style fix

* back button an android takes to the channel list page

* en.json fix

* draft actions theme compatible

* CSS fix for draft channel_info and avatar component

* removed the badge icon and change font style drafts

* fix send alert sender name for GMs

* updated snapshot

* added testId to the drafts components

* updated send draft test id

* clicking on draft takes to the channel

* Added toptip for draft tours

* intl extract

* Rebase to main and reverted local testing changes

* Added tooltip for drafts

* addressed review comments

* reset navigation when click on a draft in draft tabs

* fix the theme issue and navigation issue

* reverted back the draft click navigation changes

* observing draft when hitting back button

* removed the unwanted animiation

* updated regex for parsing markdown

* removed unnecessary checks and change folder name

* removed react memo and merge unwanted observes function

* removed unnecessary comments

* changed the name for observing and querying draft function

* removed memo from component level

* Text to FormattedText component

* Text to formatted text, change image name

* added confirmation modal for deleting draft from bottomsheet

* using common send_handler for both draft and post

* removed magic number for tooltip and bottomsheet

* renamed channel_info to draft_post_header

* text to formattedText for Edit drafts

* removed unnecessary changes

* minor fixes

* mounting draft only when there is draft

* map to reduce

* renamed SwipeableDraft to DraftSwipeAction

* name fixes

* isValidUrl to isParsableUrl and added test

* added test and addressed minor review comments

* added inline component for the duplicate code

* inlt fixes

* clearDraft is not optional

* optimised categories_list.tsx component

* Swipeable to ReanimatedSwipeable, TouchableWithoutFeedback to Pressable and folder name changes

* Added comment and disabled eslint rule for showing warning

* fixed component file name

* minor'

* Removed deprecated Animated createAnimatedComponent flatlist

* added test for missing protocol check

* import change for SwipeableMethod

* active tab for tablet view

* Updated the drafts icons

* Updated compass-icon version to v0.1.48

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
(cherry picked from commit 84eded1bde)

Co-authored-by: Rajat Dabade <rajatdabade1997@gmail.com>
2025-01-13 15:15:42 +02:00

282 lines
10 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable max-lines */
import DatabaseManager from '@database/manager';
import {
updateDraftFile,
removeDraftFile,
updateDraftMessage,
addFilesToDraft,
removeDraft,
updateDraftPriority,
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);
});
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('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);
});
});