129 lines
3.8 KiB
TypeScript
129 lines
3.8 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {cloneElement} from 'react';
|
|
import {Text, StyleSheet} from 'react-native';
|
|
|
|
import setFontFamily from './font_family';
|
|
|
|
// Type for style object
|
|
type StyleObject = { [key: string]: any };
|
|
|
|
// Custom function to flatten styles
|
|
const flattenStyles = (styles: StyleObject | Array<StyleObject | StyleObject[]>): StyleObject|undefined => {
|
|
if (styles === null || typeof styles !== 'object') {
|
|
return undefined;
|
|
}
|
|
|
|
if (!Array.isArray(styles)) {
|
|
return styles;
|
|
}
|
|
|
|
return styles.reduce((acc, style) => {
|
|
if (!style) {
|
|
return acc;
|
|
} // Skip if style is null or undefined
|
|
|
|
if (Array.isArray(style)) {
|
|
// Merge arrays of styles
|
|
return style.reduce((prev, curr) => ({
|
|
...prev,
|
|
...flattenStyles(curr),
|
|
}), acc);
|
|
} else if (typeof style === 'object') {
|
|
// Merge objects of styles
|
|
return {...acc, ...style};
|
|
}
|
|
|
|
// Skip if style is not an object or array
|
|
return acc;
|
|
}, {});
|
|
};
|
|
|
|
// Mock the necessary parts of react-native
|
|
jest.mock('react-native', () => ({
|
|
Text: {
|
|
render: jest.fn(),
|
|
},
|
|
StyleSheet: {
|
|
create: jest.fn((styles) => styles),
|
|
},
|
|
}));
|
|
|
|
// Mock cloneElement
|
|
jest.mock('react', () => ({
|
|
...jest.requireActual('react'),
|
|
cloneElement: jest.fn((element, props) => {
|
|
// Merge the existing style with the new style
|
|
const mergedStyle = flattenStyles([props.style, ...(element.props.style ? [element.props.style] : [])]);
|
|
|
|
// Return a new object with merged styles
|
|
return {
|
|
...element,
|
|
props: {
|
|
...element.props,
|
|
style: mergedStyle,
|
|
},
|
|
};
|
|
}),
|
|
}));
|
|
|
|
describe('setFontFamily', () => {
|
|
let originalTextRender: any;
|
|
|
|
beforeEach(() => {
|
|
// Capture the original Text.render before modification
|
|
// @ts-expect-error renderer is not exposed to TS definition
|
|
originalTextRender = Text.render;
|
|
});
|
|
|
|
// Restore the original implementations after each test
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
test('overrides Text.render and applies custom styles', () => {
|
|
// Call the function to set the font family
|
|
setFontFamily();
|
|
|
|
// Check if the StyleSheet.create was called with the correct styles
|
|
expect(StyleSheet.create).toHaveBeenCalledWith({
|
|
defaultText: {
|
|
fontFamily: 'OpenSans',
|
|
fontSize: 16,
|
|
},
|
|
});
|
|
|
|
// Check if Text.render was overridden
|
|
// @ts-expect-error renderer is not exposed to TS definition
|
|
expect(Text.render).not.toBe(originalTextRender);
|
|
|
|
// Create a mock origin render output
|
|
const mockOriginRenderOutput = {
|
|
props: {
|
|
style: [{color: 'red'}],
|
|
},
|
|
};
|
|
|
|
// Set the old render function to return the mock output
|
|
(originalTextRender as jest.Mock).mockReturnValue(mockOriginRenderOutput);
|
|
|
|
// Call the new render function
|
|
// @ts-expect-error renderer is not exposed to TS definition
|
|
const newRenderOutput = Text.render();
|
|
|
|
// Check if cloneElement was called with the correct arguments
|
|
expect(cloneElement).toHaveBeenCalledWith(mockOriginRenderOutput, {
|
|
style: [
|
|
{
|
|
fontFamily: 'OpenSans',
|
|
fontSize: 16,
|
|
},
|
|
[{color: 'red'}],
|
|
],
|
|
});
|
|
|
|
// Verify the new render output has the expected styles
|
|
expect(newRenderOutput.props.style).toEqual({fontFamily: 'OpenSans', fontSize: 16, color: 'red'});
|
|
});
|
|
});
|