/* * 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 { ManageTab } from '../manage_tab'; import { shallow } from 'enzyme'; import React from 'react'; import { EuiInMemoryTable } from '@elastic/eui'; import { useDeleteConfirmState } from '../../../utils/delete-confirm-modal-utils'; import { Tenant } from '../../../types'; import { TenantEditModal } from '../edit-modal'; import { TenantInstructionView } from '../tenant-instruction-view'; import { getDashboardsInfo } from '../../../../../utils/dashboards-info-utils'; jest.mock('../../../utils/tenant-utils'); jest.mock('../../../../../utils/auth-info-utils'); jest.mock('../../../utils/delete-confirm-modal-utils', () => ({ useDeleteConfirmState: jest.fn().mockReturnValue([jest.fn(), '']), })); jest.mock('../../../utils/context-menu', () => ({ useContextMenuState: jest .fn() .mockImplementation((buttonText, buttonProps, children) => [children, jest.fn()]), })); jest.mock('../../../utils/toast-utils', () => ({ useToastState: jest.fn().mockReturnValue([[], jest.fn(), jest.fn()]), getSuccessToastMessage: jest.fn(), createUnknownErrorToast: jest.fn(), })); jest.mock('../../../../../utils/dashboards-info-utils', () => ({ getDashboardsInfo: jest.fn().mockImplementation(() => { return mockDashboardsInfo; }), })); const mockDashboardsInfo = { multitenancy_enabled: true, private_tenant_enabled: true, default_tenant: '', }; // eslint-disable-next-line const mockTenantUtils = require('../../../utils/tenant-utils'); // eslint-disable-next-line const mockAuthInfoUtils = require('../../../../../utils/auth-info-utils'); describe('Tenant list', () => { const setState = jest.fn(); const mockCoreStart = { http: 1, chrome: { setBreadcrumbs() { return 1; }, }, }; const config = { multitenancy: { enabled: true, tenants: { enable_private: true, }, }, }; beforeEach(() => { jest.spyOn(React, 'useState').mockImplementation((initialValue) => [initialValue, setState]); }); it('Render empty', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return mockDashboardsInfo; }); const mockTenantListingData = [ { tenant: 'tenant_1', description: '', reserved: true, tenantValue: 'tenant_1', }, ]; mockTenantUtils.transformTenantData = jest.fn().mockReturnValue(mockTenantListingData); const component = shallow( ); expect(component.find(EuiInMemoryTable).prop('items').length).toBe(0); }); it('renders when multitenancy is disabled in the opensearch_dashboards.yml', () => { (getDashboardsInfo as jest.Mock).mockImplementation(() => { return { multitenancy_enabled: false, private_tenant_enabled: true, default_tenant: '', }; }); const config1 = { multitenancy: { enabled: false, tenants: { enable_private: true, }, }, }; const component = shallow( ); expect(component.find(TenantInstructionView).length).toBe(0); }); it('fetch data error', (done) => { jest.spyOn(React, 'useEffect').mockImplementationOnce((f) => f()); // Hide the error message jest.spyOn(console, 'log').mockImplementationOnce(() => {}); mockTenantUtils.fetchTenants.mockImplementationOnce(() => { throw Error(); }); shallow( ); process.nextTick(() => { // Expect setting error to true expect(setState).toHaveBeenCalledWith(true); done(); }); }); it('fetch data', (done) => { jest.spyOn(React, 'useEffect').mockImplementationOnce((f) => f()); const mockTenantListingData = [ { tenant: 'tenant_1', description: '', reserved: true, tenantValue: 'tenant_1', }, ]; mockTenantUtils.transformTenantData = jest.fn().mockReturnValue(mockTenantListingData); shallow( ); process.nextTick(() => { expect(mockTenantUtils.fetchTenants).toHaveBeenCalledTimes(1); expect(mockTenantUtils.transformTenantData).toHaveBeenCalledTimes(1); expect(mockTenantUtils.fetchCurrentTenant).toHaveBeenCalledTimes(1); expect(mockAuthInfoUtils.getCurrentUser).toHaveBeenCalledTimes(1); expect(setState).toHaveBeenCalledWith(mockTenantListingData); done(); }); }); it('delete tenant', (done) => { shallow( ); const deleteFunc = useDeleteConfirmState.mock.calls[0][0]; deleteFunc(); process.nextTick(() => { expect(mockTenantUtils.requestDeleteTenant).toBeCalled(); done(); }); }); it('delete tenant error', (done) => { mockTenantUtils.requestDeleteTenant.mockImplementationOnce(() => { throw new Error(); }); // Hide the error message const loggingFunc = jest.fn(); jest.spyOn(console, 'log').mockImplementationOnce(loggingFunc); shallow( ); const deleteFunc = useDeleteConfirmState.mock.calls[0][0]; deleteFunc(); process.nextTick(() => { expect(loggingFunc).toBeCalled(); done(); }); }); it('submit tenant', () => { const component = shallow( ); component.find('#createTenant').simulate('click'); const submitFunc = component.find(TenantEditModal).prop('handleSave'); submitFunc('tenant_1', ''); expect(mockTenantUtils.updateTenant).toBeCalled(); }); it('submit tenant error', () => { const consoleLog = jest.spyOn(console, 'log'); consoleLog.mockImplementation(() => {}); const error = new Error(); mockTenantUtils.updateTenant.mockImplementationOnce(() => { throw error; }); const component = shallow( ); component.find('#createTenant').simulate('click'); const submitFunc = component.find(TenantEditModal).prop('handleSave'); submitFunc('tenant_1', ''); // Expect error log expect(consoleLog).toBeCalledWith(error); }); describe('Action menu enable-disable check', () => { const sampleReservedTenant: Tenant = { tenant: 'tenant_1', description: '', reserved: true, tenantValue: 'tenant_1', }; const sampleCustomTenant1: Tenant = { tenant: 'tenant_2', description: '', reserved: false, tenantValue: 'tenant_2', }; const sampleCustomTenant2: Tenant = { tenant: 'tenant_3', description: '', reserved: false, tenantValue: 'tenant_3', }; it('edit and delete should be disabled when selected tenant is reserved', () => { jest.spyOn(React, 'useState').mockImplementation(() => [[sampleReservedTenant], jest.fn()]); const component = shallow( ); expect(component.find('#edit').prop('disabled')).toBe(true); expect(component.find('#delete').prop('disabled')).toBe(true); }); it('All menues should be disabled when there is multiple tenant selected including reserved tenant', () => { jest .spyOn(React, 'useState') .mockImplementation(() => [[sampleReservedTenant, sampleCustomTenant1], jest.fn()]); const component = shallow( ); expect(component.find('#switchTenant').prop('disabled')).toBe(true); expect(component.find('#edit').prop('disabled')).toBe(true); expect(component.find('#duplicate').prop('disabled')).toBe(true); expect(component.find('#createDashboard').prop('disabled')).toBe(true); expect(component.find('#createVisualizations').prop('disabled')).toBe(true); expect(component.find('#delete').prop('disabled')).toBe(true); }); it('All menues should be disabled except delete when there is multiple custom tenant selected', () => { jest .spyOn(React, 'useState') .mockImplementation(() => [[sampleCustomTenant1, sampleCustomTenant2], jest.fn()]); const component = shallow( ); expect(component.find('#switchTenant').prop('disabled')).toBe(true); expect(component.find('#edit').prop('disabled')).toBe(true); expect(component.find('#duplicate').prop('disabled')).toBe(true); expect(component.find('#createDashboard').prop('disabled')).toBe(true); expect(component.find('#createVisualizations').prop('disabled')).toBe(true); expect(component.find('#delete').prop('disabled')).toBe(false); }); }); describe('Action menu click', () => { let component; const sampleCustomTenant1: Tenant = { tenant: 'tenant_2', description: '', reserved: false, tenantValue: 'tenant_2', }; beforeEach(() => { jest.spyOn(React, 'useState').mockImplementation(() => [[sampleCustomTenant1], jest.fn()]); component = shallow( ); }); it('switchTenant click', () => { component.find('#switchTenant').simulate('click'); expect(mockTenantUtils.selectTenant).toBeCalled(); }); it('Edit click', () => { component.find('#edit').simulate('click'); expect(component).toMatchSnapshot(); }); it('Duplicate click', () => { component.find('#duplicate').simulate('click'); expect(component).toMatchSnapshot(); }); it('Create dashboard click', () => { component.find('#createDashboard').simulate('click'); expect(mockTenantUtils.selectTenant).toHaveBeenCalled(); }); it('Create visualizations click', () => { component.find('#createVisualizations').simulate('click'); expect(mockTenantUtils.selectTenant).toHaveBeenCalled(); }); }); });