/* * Copyright OpenSearch Contributors * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0 * * or in the "license" file accompanying this file. This file 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 { shallow } from 'enzyme'; import React from 'react'; import { fetchAccountInfo } from '../utils'; import { getDashboardsInfo } from '../../../utils/dashboards-info-utils'; import { CUSTOM_TENANT_RADIO_ID, GLOBAL_TENANT_RADIO_ID, PRIVATE_TENANT_RADIO_ID, TenantSwitchPanel, } from '../tenant-switch-panel'; import { selectTenant } from '../../configuration/utils/tenant-utils'; import { constructErrorMessageAndLog } from '../../error-utils'; import { keys } from 'lodash'; const mockAccountInfo = { data: { tenants: { ['tenant1']: true, ['global_tenant']: true, ['user1']: true, }, user_name: 'user1', roles: ['readall', 'readonly'], user_requested_tenant: '', }, }; const mockDashboardsInfo = { multitenancy_enabled: true, private_tenant_enabled: true, default_tenant: '', }; jest.mock('../utils', () => ({ fetchAccountInfo: jest.fn().mockImplementation(() => { return mockAccountInfo; }), })); jest.mock('../../../utils/dashboards-info-utils', () => ({ getDashboardsInfo: jest.fn().mockImplementation(() => { return mockDashboardsInfo; }), })); jest.mock('../../configuration/utils/tenant-utils', () => ({ ...jest.requireActual('../../configuration/utils/tenant-utils'), selectTenant: jest.fn(), })); jest.mock('../../error-utils', () => ({ constructErrorMessageAndLog: jest.fn(), })); describe('Account menu -tenant switch panel', () => { const setState = jest.fn(); const mockCoreStart = { http: 1, }; const handleClose = jest.fn(); const handleSwitchAndClose = jest.fn(); const defaultConfig = { multitenancy: { enabled: true, tenants: { enable_private: true, enable_global: true, }, }, }; const useEffect = jest.spyOn(React, 'useEffect'); const useState = jest.spyOn(React, 'useState'); beforeEach(() => { useEffect.mockImplementationOnce((f) => f()); useState.mockImplementation((initialValue) => [initialValue, setState]); (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); }); it('fetch data when user requested tenant is Global', (done) => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); shallow( ); process.nextTick(() => { expect(fetchAccountInfo).toHaveBeenCalledTimes(1); expect(setState).toHaveBeenCalledWith(keys(mockAccountInfo.data.tenants)); expect(setState).toHaveBeenCalledWith(mockAccountInfo.data.user_name); expect(setState).toHaveBeenCalledWith(GLOBAL_TENANT_RADIO_ID); done(); }); }); it('fetch data when user requested tenant is Private', (done) => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); (fetchAccountInfo as jest.Mock).mockImplementationOnce(() => { return { data: { tenants: { ['tenant1']: true, }, user_name: 'user1', roles: ['role1', 'role2'], user_requested_tenant: '__user__', }, }; }); shallow( ); process.nextTick(() => { expect(setState).toHaveBeenCalledWith(PRIVATE_TENANT_RADIO_ID); done(); }); }); it('fetch data when user requested tenant is Custom', (done) => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); (fetchAccountInfo as jest.Mock).mockImplementationOnce(() => { return { data: { tenants: { ['tenant1']: true, }, user_name: 'user1', roles: ['role1', 'role2'], user_requested_tenant: 'tenant1', }, }; }); shallow( ); process.nextTick(() => { expect(setState).toHaveBeenCalledWith(CUSTOM_TENANT_RADIO_ID); expect(setState).toHaveBeenCalledWith([{ label: 'tenant1' }]); done(); }); }); it('error occurred while fetching data', (done) => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); (fetchAccountInfo as jest.Mock).mockImplementationOnce(() => { throw new Error(); }); const spy = jest.spyOn(console, 'error').mockImplementationOnce(() => {}); shallow( ); process.nextTick(() => { expect(spy).toHaveBeenCalled(); done(); }); }); it('handle modal close', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); const component = shallow( ); component.find('[data-test-subj="tenant-switch-modal"]').simulate('close'); expect(handleClose).toBeCalled(); }); it('Confirm button should be disabled when multitenancy is disabled in Config', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return { multitenancy_enabled: false, private_tenant_enabled: true, default_tenant: '', }; }); const config = { multitenancy: { enabled: false, tenants: { enable_private: true, enable_global: true, }, }, }; const component = shallow( ); process.nextTick(() => { const confirmButton = component.find('[data-test-subj="confirm"]'); expect(confirmButton.prop('disabled')).toBe(true); }); }); it('selected radio id should be change on onChange event', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); const component = shallow( ); component .find('[data-test-subj="tenant-switch-radios"]') .simulate('change', GLOBAL_TENANT_RADIO_ID); expect(setState).toBeCalledWith(GLOBAL_TENANT_RADIO_ID); expect(setState).toBeCalledWith(''); }); it('should set error call out when tenant name is undefined', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); const component = shallow( ); component.find('[data-test-subj="confirm"]').simulate('click'); expect(setState).toBeCalledWith('No target tenant is specified!'); }); describe('confirm button and renders', () => { beforeEach(() => { useState.mockImplementationOnce(() => [keys(mockAccountInfo.data.tenants), setState]); useState.mockImplementationOnce(() => [mockAccountInfo.data.user_name, setState]); }); it('should handle tenant confirmation on "confirm" button click when selected tenant is Global tenant', () => { useState.mockImplementationOnce(() => [[], setState]); useState.mockImplementationOnce(() => ['', setState]); useState.mockImplementationOnce(() => [GLOBAL_TENANT_RADIO_ID, setState]); useState.mockImplementationOnce(() => ['', setState]); const component = shallow( ); component.find('[data-test-subj="confirm"]').simulate('click'); expect(selectTenant).toHaveBeenCalledTimes(1); }); it('should handle tenant confirmation on "confirm" button click when selected tenant is Private tenant', () => { useState.mockImplementationOnce(() => [[], setState]); useState.mockImplementationOnce(() => ['', setState]); useState.mockImplementationOnce(() => [PRIVATE_TENANT_RADIO_ID, setState]); useState.mockImplementationOnce(() => ['', setState]); const component = shallow( ); component.find('[data-test-subj="confirm"]').simulate('click'); expect(selectTenant).toHaveBeenCalledTimes(1); }); it('should handle tenant confirmation on "confirm" button click when selected tenant is Custom tenant', () => { useState.mockImplementationOnce(() => [[], setState]); useState.mockImplementationOnce(() => ['', setState]); useState.mockImplementationOnce(() => [CUSTOM_TENANT_RADIO_ID, setState]); useState.mockImplementationOnce(() => [[{ label: 'tenant1' }], setState]); const component = shallow( ); component.find('[data-test-subj="confirm"]').simulate('click'); expect(selectTenant).toHaveBeenCalledTimes(1); }); it('should set error call out when error occurred while changing the tenant', (done) => { useState.mockImplementationOnce(() => [[], setState]); useState.mockImplementationOnce(() => ['', setState]); useState.mockImplementationOnce(() => [GLOBAL_TENANT_RADIO_ID, setState]); useState.mockImplementationOnce(() => ['', setState]); (selectTenant as jest.Mock).mockImplementationOnce(() => { throw Error(); }); const component = shallow( ); component.find('[data-test-subj="confirm"]').simulate('click'); process.nextTick(() => { expect(constructErrorMessageAndLog).toHaveBeenCalledTimes(1); done(); }); }); it('renders when both global and private tenant enabled', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); const component = shallow( ); expect(component).toMatchSnapshot(); }); it('renders when global tenant disabled', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); const config = { multitenancy: { enabled: true, tenants: { enable_private: true, enable_global: false, }, }, }; const component = shallow( ); expect(component).toMatchSnapshot(); }); it('renders when private tenant disabled', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return { multitenancy_enabled: true, private_tenant_enabled: false, default_tenant: '', }; }); const config = { multitenancy: { enabled: true, tenants: { enable_private: false, enable_global: true, }, }, }; const component = shallow( ); expect(component).toMatchSnapshot(); }); it('renders when user has read only role', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); useState.mockImplementationOnce(() => [['readonly'], setState]); useState.mockImplementationOnce(() => ['', setState]); const config = { readonly_mode: { roles: ['readonly'], }, multitenancy: { enabled: true, tenants: { enable_private: true, enable_global: true, }, }, }; const component = shallow( ); expect(component).toMatchSnapshot(); }); it('renders when user has default read only role', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); useState.mockImplementationOnce(() => [['kibana_read_only'], setState]); useState.mockImplementationOnce(() => ['', setState]); const config = { readonly_mode: { roles: [], }, multitenancy: { enabled: true, tenants: { enable_private: true, enable_global: true, }, }, }; const component = shallow( ); expect(component).toMatchSnapshot(); }); }); });