/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. * * Any modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import React from 'react'; import { act } from 'react-dom/test-utils'; import { Subject } from 'rxjs'; import { share } from 'rxjs/operators'; import { ReactExpressionRenderer } from './react_expression_renderer'; import { ExpressionLoader } from './loader'; import { mount } from 'enzyme'; import { EuiProgress } from '@elastic/eui'; import { RenderErrorHandlerFnType } from './types'; import { ExpressionRendererEvent } from './render'; jest.mock('./loader', () => { return { ExpressionLoader: jest.fn().mockImplementation(() => { return {}; }), loader: jest.fn(), }; }); describe('ExpressionRenderer', () => { it('starts to load, resolves, and goes back to loading', () => { const dataSubject = new Subject(); const data$ = dataSubject.asObservable().pipe(share()); const renderSubject = new Subject(); const render$ = renderSubject.asObservable().pipe(share()); const loadingSubject = new Subject(); const loading$ = loadingSubject.asObservable().pipe(share()); (ExpressionLoader as jest.Mock).mockImplementation(() => { return { render$, data$, loading$, update: jest.fn(), }; }); const instance = mount(); act(() => { loadingSubject.next(); }); instance.update(); expect(instance.find(EuiProgress)).toHaveLength(1); act(() => { renderSubject.next(1); }); instance.update(); expect(instance.find(EuiProgress)).toHaveLength(0); instance.setProps({ expression: 'something new' }); act(() => { loadingSubject.next(); }); instance.update(); expect(instance.find(EuiProgress)).toHaveLength(1); act(() => { renderSubject.next(1); }); instance.update(); expect(instance.find(EuiProgress)).toHaveLength(0); }); it('updates the expression loader when refresh subject emits', () => { const refreshSubject = new Subject(); const loaderUpdate = jest.fn(); (ExpressionLoader as jest.Mock).mockImplementation(() => { return { render$: new Subject(), data$: new Subject(), loading$: new Subject(), update: loaderUpdate, destroy: jest.fn(), }; }); const instance = mount(); act(() => { refreshSubject.next(); }); expect(loaderUpdate).toHaveBeenCalled(); instance.unmount(); }); it('should display a custom error message if the user provides one and then remove it after successful render', () => { const dataSubject = new Subject(); const data$ = dataSubject.asObservable().pipe(share()); const renderSubject = new Subject(); const render$ = renderSubject.asObservable().pipe(share()); const loadingSubject = new Subject(); const loading$ = loadingSubject.asObservable().pipe(share()); let onRenderError: RenderErrorHandlerFnType; (ExpressionLoader as jest.Mock).mockImplementation((...args) => { const params = args[2]; onRenderError = params.onRenderError; return { render$, data$, loading$, update: jest.fn(), }; }); const instance = mount(
{message}
} /> ); act(() => { onRenderError!(instance.getDOMNode(), new Error('render error'), { done: () => { renderSubject.next(1); }, } as any); }); instance.update(); expect(instance.find(EuiProgress)).toHaveLength(0); expect(instance.find('[data-test-subj="custom-error"]')).toHaveLength(1); expect(instance.find('[data-test-subj="custom-error"]').contains('render error')).toBeTruthy(); act(() => { loadingSubject.next(); renderSubject.next(2); }); instance.update(); expect(instance.find(EuiProgress)).toHaveLength(0); expect(instance.find('[data-test-subj="custom-error"]')).toHaveLength(0); }); it('should fire onEvent prop on every events$ observable emission in loader', () => { const dataSubject = new Subject(); const data$ = dataSubject.asObservable().pipe(share()); const renderSubject = new Subject(); const render$ = renderSubject.asObservable().pipe(share()); const loadingSubject = new Subject(); const loading$ = loadingSubject.asObservable().pipe(share()); const eventsSubject = new Subject(); const events$ = eventsSubject.asObservable().pipe(share()); const onEvent = jest.fn(); const event: ExpressionRendererEvent = { name: 'foo', data: { bar: 'baz', }, }; (ExpressionLoader as jest.Mock).mockImplementation(() => { return { render$, data$, loading$, events$, update: jest.fn(), }; }); mount(); expect(onEvent).toHaveBeenCalledTimes(0); act(() => { eventsSubject.next(event); }); expect(onEvent).toHaveBeenCalledTimes(1); expect(onEvent.mock.calls[0][0]).toBe(event); }); });