/*
* 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);
});
});