import { fireEvent, render, waitFor } from '@testing-library/react-native';
import {
DeviceEventEmitter,
LayoutChangeEvent,
Platform,
Text,
View,
} from 'react-native';
import WebView from 'react-native-webview';
import Logger from '../../core/logging/logger';
import { CSWebView } from '../../webview/CSWebView.android';
import { injectWebView, removeWebViewInjection } from '../../webview/webView';
jest.mock('../../core/logging/logger', () => ({
error: jest.fn(),
warn: jest.fn(),
}));
jest.mock('../../webview/webView', () => ({
injectWebView: jest.fn(),
removeWebViewInjection: jest.fn(),
}));
jest.mock('react-native-webview', () => ({
__esModule: true,
default: 'WebView',
}));
describe('CSWebView', () => {
beforeEach(() => {
Platform.OS = 'android';
jest.clearAllMocks();
});
afterEach(() => {
jest.restoreAllMocks();
jest.restoreAllMocks();
});
describe('Implementation 2: Child WebView', () => {
it('should render a child webview with the correct props', () => {
const mockOnLayout = jest.fn();
const { getByTestId } = render(
);
const childWebView = getByTestId('child-webview');
expect(childWebView).toBeTruthy();
});
it('should log an error if more than one child is passed', () => {
render(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - Testing with multiple children
);
expect(Logger.error).toHaveBeenCalledWith(
'CSWebView component expects exactly 1 child, but received multiple. Ensure that only a single child element is passed'
);
});
it('should inject webview on layout', () => {
const mockEvent = {
nativeEvent: { target: 123 },
} as unknown as LayoutChangeEvent;
const { getByTestId } = render(
);
const childWebView = getByTestId('child-webview');
fireEvent(childWebView, 'layout', mockEvent);
expect(injectWebView).toHaveBeenCalledWith(123);
});
it('should call onLayout prop from children', () => {
const mockOnLayout = jest.fn();
const { getByTestId } = render(
);
const childWebView = getByTestId('child-webview');
fireEvent(childWebView, 'layout', {
nativeEvent: { layout: { width: 100, height: 100 } },
});
expect(mockOnLayout).toHaveBeenCalled();
});
it('should set applicationNameForUserAgent to "CS_WebView" when no original applicationNameForUserAgent is provided', () => {
const { getByTestId } = render(
);
const webView = getByTestId('webview');
expect(webView.props.applicationNameForUserAgent).toContain('CS_WebView');
});
it('should append "CS_WebView" to existing userAgent', () => {
const originalUserAgent = 'Mozilla/5.0 (Linux; Android 10; SM-G975F)';
const { getByTestId } = render(
);
const webView = getByTestId('webview');
expect(webView.props.applicationNameForUserAgent).toContain(`${originalUserAgent} CS_WebView`);
});
it('should work with empty string applicationNameForUserAgent', () => {
const { getByTestId } = render(
);
const webView = getByTestId('webview');
expect(webView.props.applicationNameForUserAgent).toContain('CS_WebView');
});
it('should work with undefined userAgent', () => {
const { getByTestId } = render(
);
const webView = getByTestId('webview');
expect(webView.props.applicationNameForUserAgent).toContain('CS_WebView');
});
});
it('should remove onCSWebViewInjectedListener on unmount', () => {
const mockRenderWebView = jest.fn((onLayout, webViewUrl) => (
{webViewUrl}
));
const removeListener = jest.fn();
jest.spyOn(DeviceEventEmitter, 'addListener').mockImplementation(() => ({
remove: removeListener,
}));
const { unmount } = render(
);
unmount();
expect(removeListener).toHaveBeenCalled();
});
it('should call removeWebViewInjection on unmount', async () => {
const { getByTestId, unmount } = render(
);
const childWebView = getByTestId('child-webview');
fireEvent(childWebView, 'layout', {
nativeEvent: { layout: { width: 100, height: 100 }, target: 123 },
});
await waitFor(() => expect(injectWebView).toHaveBeenCalledWith(123));
DeviceEventEmitter.emit('onCSWebViewInjected');
unmount();
await waitFor(() => expect(removeWebViewInjection).toHaveBeenCalled());
});
});