diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js
index ee2b9b43d9a..8731294ffbb 100644
--- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js
+++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Users.spec.js
@@ -27,6 +27,28 @@ const userEmail = `${userName}@gmail.com`;
const adminName = `Admincttest${uuid()}`;
const adminEmail = `${adminName}@gmail.com`;
+const searchBotText = 'bot';
+
+const searchBotUser = () => {
+ // Search the bot user
+ interceptURL(
+ 'GET',
+ `/api/v1/search/query?q=*${searchBotText}***(isBot:false)&from=0&size=15&index=user_search_index`,
+ 'searchUser'
+ );
+ cy.get('[data-testid="searchbar"]')
+ .should('exist')
+ .should('be.visible')
+ .type(searchBotText);
+
+ verifyResponseStatusCode('@searchUser', 200);
+
+ cy.get('.ant-table-placeholder > .ant-table-cell').should(
+ 'not.contain',
+ searchBotText
+ );
+};
+
describe('Users flow should work properly', () => {
beforeEach(() => {
cy.login();
@@ -75,6 +97,10 @@ describe('Users flow should work properly', () => {
softDeleteUser(userName);
deleteSoftDeletedUser(userName);
});
+
+ it('Search bot user', () => {
+ searchBotUser();
+ });
});
describe('Admin flow should work properly', () => {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.test.tsx
new file mode 100644
index 00000000000..7f05afa6f22
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.test.tsx
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2022 Collate.
+ * Licensed 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 { cleanup, render, screen } from '@testing-library/react';
+import { MOCK_USER_DATA } from 'pages/UserListPage/mockUserData';
+import React from 'react';
+import { MemoryRouter } from 'react-router-dom';
+import { act } from 'react-test-renderer';
+import UserListV1 from './UserListV1';
+
+jest.mock('rest/userAPI', () => ({
+ updateUser: jest.fn().mockImplementation(() => Promise.resolve()),
+}));
+
+jest.mock('../../generated/api/teams/createUser', () => ({
+ CreateUser: jest.fn().mockImplementation(() => Promise.resolve()),
+}));
+
+jest.mock('../../utils/ToastUtils', () => ({
+ showErrorToast: jest.fn(),
+ showSuccessToast: jest.fn(),
+}));
+
+jest.mock('../common/DeleteWidget/DeleteWidgetModal', () => {
+ return jest.fn().mockImplementation(() =>
DeleteWidgetModal
);
+});
+
+jest.mock('../common/error-with-placeholder/ErrorPlaceHolder', () => {
+ return jest.fn().mockImplementation(() => ErrorPlaceHolder
);
+});
+
+jest.mock('../common/next-previous/NextPrevious', () => {
+ return jest.fn().mockImplementation(() => NextPrevious
);
+});
+
+jest.mock('../header/PageHeader.component', () => {
+ return jest.fn().mockImplementation(() => PageHeader
);
+});
+
+jest.mock('../Loader/Loader', () => {
+ return jest.fn().mockImplementation(() => Loader
);
+});
+
+jest.mock('../common/searchbar/Searchbar', () => {
+ return jest
+ .fn()
+ .mockImplementation((prop) => (
+ prop.onSearch(e.target.value)}
+ />
+ ));
+});
+
+const mockFunction = jest.fn();
+
+const MOCK_PROPS_DATA = {
+ data: MOCK_USER_DATA.data,
+ paging: MOCK_USER_DATA.paging,
+ searchTerm: '',
+ currentPage: 1,
+ isDataLoading: false,
+ showDeletedUser: false,
+ onSearch: mockFunction,
+ onShowDeletedUserChange: mockFunction,
+ onPagingChange: mockFunction,
+ afterDeleteAction: mockFunction,
+ isAdminPage: false,
+};
+
+describe('Test UserListV1 component', () => {
+ beforeEach(() => {
+ cleanup();
+ });
+
+ it('should render component', async () => {
+ await act(async () => {
+ render(, {
+ wrapper: MemoryRouter,
+ });
+ });
+
+ const userListComponent = await screen.findByTestId(
+ 'user-list-v1-component'
+ );
+ const pageHeader = await screen.findByText('PageHeader');
+
+ expect(userListComponent).toBeInTheDocument();
+ expect(pageHeader).toBeInTheDocument();
+ });
+
+ it('should render ErrorPlaceHolder', async () => {
+ await act(async () => {
+ render(, {
+ wrapper: MemoryRouter,
+ });
+ });
+
+ const emptyComponent = await screen.findByText('ErrorPlaceHolder');
+
+ expect(emptyComponent).toBeInTheDocument();
+ });
+
+ it('should render Users table', async () => {
+ await act(async () => {
+ render(, {
+ wrapper: MemoryRouter,
+ });
+ });
+
+ const userListComponent = await screen.findByTestId(
+ 'user-list-v1-component'
+ );
+
+ expect(userListComponent).toBeInTheDocument();
+
+ const table = await screen.findByTestId('user-list-table');
+
+ expect(table).toBeInTheDocument();
+
+ const userName = await screen.findByText('label.username');
+ const teams = await screen.findByText('label.team-plural');
+ const role = await screen.findByText('label.role-plural');
+
+ expect(userName).toBeInTheDocument();
+ expect(teams).toBeInTheDocument();
+ expect(role).toBeInTheDocument();
+
+ const rows = await screen.findAllByRole('row');
+
+ expect(rows).toHaveLength(MOCK_PROPS_DATA.data.length + 1);
+ });
+
+ it('Should not render data when bot is search', async () => {
+ await act(async () => {
+ render(, {
+ wrapper: MemoryRouter,
+ });
+ });
+
+ const userListComponent = await screen.findByTestId(
+ 'user-list-v1-component'
+ );
+
+ expect(userListComponent).toBeInTheDocument();
+
+ const table = await screen.findByTestId('user-list-table');
+
+ const noDataTable = await screen.findByText('No data');
+
+ expect(table).toBeInTheDocument();
+ expect(noDataTable).toBeInTheDocument();
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx
index 53a3ff061ac..90f5ecca03c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx
@@ -220,7 +220,10 @@ const UserListV1: FC = ({
}
return (
-
+
= ({
bordered
className="user-list-table"
columns={columns}
+ data-testid="user-list-table"
dataSource={data}
loading={{
spinning: isDataLoading,
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx
index 5166b7a3985..1d62ccc2269 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/UserListPage/UserListPageV1.tsx
@@ -102,7 +102,7 @@ const UserListPageV1 = () => {
isAdmin = false,
isDeleted = false
) => {
- let filters = '';
+ let filters = '(isBot:false)';
if (isAdmin) {
filters = '(isAdmin:true)';
}