Skip to content

Commit

Permalink
add unit tests to app/utils/markdown (#8135)
Browse files Browse the repository at this point in the history
  • Loading branch information
enahum authored Aug 12, 2024
1 parent 0b83938 commit 5261e29
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 3 deletions.
203 changes: 203 additions & 0 deletions app/utils/markdown/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {Platform, type TextStyle} from 'react-native';

import {Preferences} from '@constants';

import {
getCodeFont,
getMarkdownTextStyles,
getMarkdownBlockStyles,
getHighlightLanguageFromNameOrAlias,
getHighlightLanguageName,
escapeRegex,
getMarkdownImageSize,
computeTextStyle,
parseSearchTerms,
convertSearchTermToRegex,
} from './index';

jest.mock('@utils/images', () => ({
getViewPortWidth: jest.fn(),
}));

jest.mock('@utils/log', () => ({
logError: jest.fn(),
}));

describe('Utility functions', () => {
describe('getCodeFont', () => {
it('should return the correct font for iOS', () => {
Platform.OS = 'ios';
expect(getCodeFont()).toBe('Menlo');
});

it('should return the correct font for Android', () => {
Platform.OS = 'android';
expect(getCodeFont()).toBe('monospace');
});
});

describe('getMarkdownTextStyles', () => {
it('should return correct text styles', () => {
const styles = getMarkdownTextStyles(Preferences.THEMES.denim);
expect(styles).toHaveProperty('emph');
expect(styles).toHaveProperty('strong');
expect(styles).toHaveProperty('del');
expect(styles).toHaveProperty('link');
expect(styles).toHaveProperty('heading1');
expect(styles).toHaveProperty('code');
expect(styles).toHaveProperty('mention');
expect(styles).toHaveProperty('error');
expect(styles).toHaveProperty('table_header_row');
expect(styles).toHaveProperty('mention_highlight');
});
});

describe('getMarkdownBlockStyles', () => {
it('should return correct block styles', () => {
const styles = getMarkdownBlockStyles(Preferences.THEMES.denim);
expect(styles).toHaveProperty('adjacentParagraph');
expect(styles).toHaveProperty('horizontalRule');
expect(styles).toHaveProperty('quoteBlockIcon');
});
});

describe('getHighlightLanguageFromNameOrAlias', () => {
it('should return correct language name or alias', () => {
expect(getHighlightLanguageFromNameOrAlias('javascript')).toBe('javascript');
expect(getHighlightLanguageFromNameOrAlias('js')).toBe('javascript');
expect(getHighlightLanguageFromNameOrAlias('unknown')).toBe('');
});
});

describe('getHighlightLanguageName', () => {
it('should return correct language name', () => {
expect(getHighlightLanguageName('javascript')).toBe('JavaScript');
expect(getHighlightLanguageName('unknown')).toBe('');
});
});

describe('escapeRegex', () => {
it('should escape special regex characters', () => {
expect(escapeRegex('hello.*')).toBe('hello\\.\\*');
});
});

describe('getMarkdownImageSize', () => {
it('should return correct size for sourceSize', () => {
const size = getMarkdownImageSize(false, false, {width: 100, height: 200});
expect(size).toEqual({width: 100, height: 200});
});

it('should return correct size for sourceSize without height', () => {
const size = getMarkdownImageSize(false, false, {width: 100});
expect(size).toEqual({width: 100, height: 100});
});

it('should return correct size for sourceSize without height and known size', () => {
const size = getMarkdownImageSize(false, false, {width: 100}, {width: 100, height: 200});
expect(size).toEqual({width: 100, height: 200});
});

it('should return correct size for sourceSize height height and known size', () => {
const size = getMarkdownImageSize(false, false, {height: 100}, {width: 100, height: 200});
expect(size).toEqual({width: 50, height: 100});
});

it('should return correct size for knownSize', () => {
const size = getMarkdownImageSize(false, false, undefined, {width: 100, height: 200});
expect(size).toEqual({width: 100, height: 200});
});

it('should return correct size when no metadata and source size is not specified', () => {
const size = getMarkdownImageSize(false, false, undefined, undefined, 150, 250);
expect(size).toEqual({width: 150, height: 250});
});
});

describe('computeTextStyle', () => {
const textStyles: { [key: string]: TextStyle } = {
bold: {fontWeight: 'bold'},
italic: {fontStyle: 'italic'},
underline: {textDecorationLine: 'underline'},
};

const baseStyle: TextStyle = {color: 'black'};

it('should return base style if context is empty', () => {
expect(computeTextStyle(textStyles, baseStyle, [])).toEqual(baseStyle);
});

it('should return base style if context has no matching styles', () => {
expect(computeTextStyle(textStyles, baseStyle, ['unknown'])).toEqual(baseStyle);
});

it('should apply a single context style', () => {
expect(computeTextStyle(textStyles, baseStyle, ['bold'])).toEqual([baseStyle, textStyles.bold]);
});

it('should apply multiple context styles', () => {
expect(computeTextStyle(textStyles, baseStyle, ['bold', 'italic'])).toEqual([baseStyle, textStyles.bold, textStyles.italic]);
});

it('should ignore undefined styles', () => {
expect(computeTextStyle(textStyles, baseStyle, ['bold', 'unknown'])).toEqual([baseStyle, textStyles.bold]);
});

it('should handle multiple undefined styles', () => {
expect(computeTextStyle(textStyles, baseStyle, ['unknown1', 'unknown2'])).toEqual(baseStyle);
});
});

describe('parseSearchTerms', () => {
it('should capture quoted strings', () => {
expect(parseSearchTerms('"hello world"')).toEqual(['hello world']);
});

it('should ignore search flags', () => {
expect(parseSearchTerms('in:channel before:2021-01-01')).toEqual([]);
});

it('should capture @ mentions', () => {
expect(parseSearchTerms('@username')).toEqual(['username']);
});

it('should capture plain text up to the next quote or search flag', () => {
expect(parseSearchTerms('plain text "quoted text"')).toEqual(['plain', 'text', 'quoted text']);
});

it('should split plain text into words', () => {
expect(parseSearchTerms('this is a test')).toEqual(['this', 'is', 'a', 'test']);
});

it('should handle a mix of all cases', () => {
const searchTerm = 'in:channel @username "quoted text" plain text';
const expected = ['username', 'quoted text', 'plain', 'text'];
expect(parseSearchTerms(searchTerm)).toEqual(expected);
});
});

describe('convertSearchTermToRegex', () => {
it('should create regex for CJK characters', () => {
const result = convertSearchTermToRegex('你好');
expect(result.pattern).toEqual(/()(你好)/gi);
});

it('should create regex for wildcard at the end', () => {
const result = convertSearchTermToRegex('hello*');
expect(result.pattern).toEqual(/\b()(hello)/gi);
});

it('should create regex for mentions and hashtags', () => {
const result = convertSearchTermToRegex('@user');
expect(result.pattern).toEqual(/(\W|^)(@user)\b/gi);
});

it('should create regex for plain text', () => {
const result = convertSearchTermToRegex('hello');
expect(result.pattern).toEqual(/\b()(hello)\b/gi);
});
});
});
7 changes: 4 additions & 3 deletions app/utils/markdown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,11 @@ export function parseSearchTerms(searchTerm: string): string[] | undefined {
}

// remove punctuation from each term
terms = terms.map((term) => {
term.replace(puncStart, '');
terms = terms.map((t) => {
let term = t;
term = term.replace(puncStart, '');
if (term.charAt(term.length - 1) !== '*') {
term.replace(puncEnd, '');
term = term.replace(puncEnd, '');
}
return term;
});
Expand Down

0 comments on commit 5261e29

Please sign in to comment.