Cypress: E2E testing for teams and users page (#5103)

* initial setup

* added teams e2e flow

* fix some fliky test

* removed only key word

* added users page flow

* removed 'only' key word

* wait time fix
This commit is contained in:
Shailesh Parmar 2022-05-24 18:55:17 +05:30 committed by GitHub
parent a694dd5a04
commit b8f3e42e58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 558 additions and 23 deletions

View File

@ -11,7 +11,7 @@
* limitations under the License.
*/
const uuid = () => Cypress._.random(0, 1e6);
export const uuid = () => Cypress._.random(0, 1e6);
const isDatabaseService = (type) => type === 'database';

View File

@ -11,6 +11,8 @@
* limitations under the License.
*/
import { uuid } from '../common/common';
export const MYDATA_SUMMARY_OPTIONS = {
tables: 'tables',
topics: 'topics',
@ -87,3 +89,35 @@ export const FOLLOWING_TITLE = 'Following';
export const NO_SEARCHED_TERMS = 'No searched terms';
export const DELETE_TERM = 'DELETE';
export const TOTAL_SAMPLE_DATA_TEAMS_COUNT = 7;
export const TEAMS = {
Cloud_Infra: { name: 'Cloud_Infra', users: 15 },
Customer_Support: { name: 'Customer_Support', users: 20 },
Data_Platform: { name: 'Data_Platform', users: 16 },
};
export const NEW_TEAM = {
team_1: {
name: 'account',
display_name: 'Account',
description: 'Account department',
},
team_2: {
name: 'service',
display_name: 'Service',
description: 'Service department',
},
};
const id = uuid();
export const NEW_USER = {
email: `test_${id}@gmail.com`,
display_name: `Test user ${id}`,
description: 'Hello, I am test user',
};
export const NEW_ADMIN = {
email: `test_${id}@gmail.com`,
display_name: `Test admin ${id}`,
description: 'Hello, I am test admin',
};

View File

@ -61,8 +61,11 @@ describe('Entity Details Page', () => {
cy.get('@confirmBtn').click();
// success modal should be visible
cy.contains('Entity deleted successfully!').should('be.visible');
cy.get('.Toastify__close-button > svg').first().should('be.visible').click();
cy.contains('deleted successfully!').should('be.visible');
cy.get('.Toastify__close-button > svg')
.first()
.should('be.visible')
.click();
cy.get('[data-testid="message-container"]')
.first()
@ -78,7 +81,10 @@ describe('Entity Details Page', () => {
.should('be.visible')
.should('contain', `${singuler} instance for ${fqn} not found`);
cy.get('.Toastify__close-button > svg').first().should('be.visible').click();
cy.get('.Toastify__close-button > svg')
.first()
.should('be.visible')
.click();
cy.get('[data-testid="no-data-image"]').should('be.visible');
cy.contains(
`${Cypress._.startCase(singuler)} instance for ${fqn} not found`

View File

@ -0,0 +1,479 @@
/*
* Copyright 2021 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 { searchEntity } from '../../common/common';
import { DELETE_TERM, NEW_TEAM, NEW_USER, SEARCH_ENTITY_TABLE, TEAMS, TOTAL_SAMPLE_DATA_TEAMS_COUNT } from '../../constants/constants';
describe('TeamsAndUsers page', () => {
beforeEach(() => {
cy.goToHomePage();
cy.get('[data-testid="terms"]').should('be.visible').click();
});
const seletctTeam = (name) => {
cy.get(`[data-testid="team-${name}"]`).should('be.visible').click();
cy.get(`[data-testid="team-${name}"] > .tw-group`).should(
'have.class',
'activeCategory'
);
};
const toastNotification = (msg) => {
cy.get('.Toastify__toast-body').should('be.visible').contains(msg);
cy.get('.Toastify__close-button > svg > path').should('be.visible').click();
};
const createNewTeam = (data) => {
cy.get('[data-testid="add-team-button"]').should('be.visible').click();
cy.get('.tw-modal-container').should('be.visible');
cy.get('[data-testid="name"]').should('be.visible').type(data.name);
cy.get('[data-testid="displayName"]')
.should('be.visible')
.type(data.display_name);
cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror')
.should('be.visible')
.type(data.description);
cy.get('[data-testid="saveButton"]')
.should('be.visible')
.scrollIntoView()
.click();
cy.get(`[data-testid="team-${TEAMS.Cloud_Infra.name}"]`).should(
'be.visible'
);
};
const deleteNewTeam = (data) => {
seletctTeam(data.name);
cy.get('[data-testid="Manage"]').should('be.visible').click();
cy.get('[data-testid="hard-delete"]')
.should('be.visible')
.as('hardDeleteContainer');
cy.get('@hardDeleteContainer')
.find('[data-testid="delete-button"]')
.should('be.visible')
.click();
cy.get('[data-testid="confirmation-text-input"]')
.should('be.visible')
.type(DELETE_TERM);
cy.get('[data-testid="confirm-button"]')
.should('be.visible')
.should('not.be.disabled')
.click();
toastNotification('Team deleted successfully!');
};
it('All the required details should render properly', () => {
cy.get('[data-testid="team-name"]').should(
'have.length',
TOTAL_SAMPLE_DATA_TEAMS_COUNT
);
cy.get(`[data-testid="team-${TEAMS.Cloud_Infra.name}"] > .tw-group`).should(
'have.class',
'activeCategory'
);
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.invoke('text')
.then((text) => {
expect(text).equal(TEAMS.Cloud_Infra.name);
});
});
it('Add new team flow should work properly', () => {
const newTeams = Object.values(NEW_TEAM);
newTeams.forEach((team) => {
createNewTeam(team);
});
cy.get('[data-testid="team-name"]').should(
'have.length',
TOTAL_SAMPLE_DATA_TEAMS_COUNT + newTeams.length
);
});
it('Description and display name updation should work properly', () => {
const updatedName = 'Account_department';
const updatedDescription = 'New description';
cy.get('[data-testid="edit-synonyms"]').should('be.visible').click();
cy.get('[data-testid="synonyms"]')
.should('be.visible')
.clear()
.type(updatedName);
cy.get('[data-testid="saveAssociatedTag"]').should('be.visible').click();
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.invoke('text')
.then((text) => {
expect(text).equal(updatedName);
});
cy.get('[data-testid="edit-description"] > [data-testid="image"]')
.should('be.visible')
.click();
cy.get('.tw-modal-container').should('be.visible');
cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror')
.should('be.visible')
.clear()
.type(updatedDescription);
cy.get('[data-testid="save"]').should('be.visible').click();
cy.get('[data-testid="viewer-container"]')
.contains(updatedDescription)
.should('exist');
});
it('Add and remove user to team should work properly', () => {
const searchString = 'aaron';
cy.wait(1000)
cy.get('[data-testid="add-new-user"]').should('be.visible');
cy.get('[data-testid="add-new-user"]').click();
cy.get('.tw-modal-container').should('be.visible');
cy.get(
'.tw-modal-body > [data-testid="search-bar-container"] > .tw-flex > [data-testid="searchbar"]'
)
.should('be.visible')
.type(searchString);
cy.get('.tw-grid').children().its('length').should('be.gt', 0);
cy.get('[data-testid="checkboxAddUser"]').eq(1).check();
cy.get('[data-testid="AddUserSave"]').should('be.visible').click();
cy.get('[data-testid="user-card-container"]').should('be.visible');
// remove user from team
cy.get('[data-testid="remove"]').first().should('be.visible').click();
cy.get('.tw-modal-container').should('be.visible');
cy.get('[data-testid="body-text"]')
.contains('Are you sure you want to remove')
.should('be.visible');
cy.get('[data-testid="save-button"]').should('be.visible').click();
cy.get('.tw-modal-container').should('not.exist');
cy.get('[data-testid="add-new-user"]').should('be.visible');
});
it('Delete team flow should work properly', () => {
const newTeams = Object.values(NEW_TEAM);
newTeams.forEach((team) => {
deleteNewTeam(team);
});
});
it('Join team flow should work properly', () => {
seletctTeam(TEAMS.Customer_Support.name);
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.invoke('text')
.then((text) => {
expect(text).equal(TEAMS.Customer_Support.name);
});
cy.get('[data-testid="join-teams"]').should('be.visible').click();
toastNotification('Team joined successfully!');
// get current user name and search user list
cy.get(
'[data-testid="dropdown-profile"] > [data-testid="dropdown-item"] > :nth-child(1) > [data-testid="menu-button"]'
)
.should('be.visible')
.click();
cy.get('[data-testid="greeting-text"] > a > :nth-child(1)')
.should('be.visible')
.invoke('text')
.then((name) => {
cy.get('[data-testid="dropdown-item"] > .tw-z-10').click();
cy.get('[data-testid="searchbar"]').should('be.visible').type(name);
cy.get('.tw-grid > [data-testid="user-card-container"]')
.should('be.visible')
.contains(name)
.should('exist');
});
});
it('Leave team flow should work properly', () => {
seletctTeam(TEAMS.Customer_Support.name);
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.invoke('text')
.then((text) => {
expect(text).equal(TEAMS.Customer_Support.name);
});
cy.get('[data-testid="join-teams"]').should('not.exist');
cy.get('[data-testid="leave-team-button"]').should('be.visible').click();
cy.get('.tw-modal-container')
.should('be.visible')
.contains(
`Are you sure you want to leave the team ${TEAMS.Customer_Support.name}?`
)
.should('exist');
cy.get('[data-testid="save-button"]').should('be.visible').click();
toastNotification('Left the team successfully!');
// This need to be un-commented once ES issue is resoved
// cy.get(
// '[data-testid="dropdown-profile"] > [data-testid="dropdown-item"] > :nth-child(1) > [data-testid="menu-button"]'
// )
// .should('be.visible')
// .click();
// cy.get('[data-testid="greeting-text"] > a > :nth-child(1)')
// .should('be.visible')
// .invoke('text')
// .then((name) => {
// cy.get('[data-testid="dropdown-item"] > .tw-z-10').click();
// cy.get('[data-testid="searchbar"]').should('be.visible').type(name);
// cy.contains(`There are no users as ${name}.`).should('exist');
// });
cy.get('[data-testid="Users"] > .tw-py-px > [data-testid="filter-count"]')
.should('be.visible')
.invoke('text')
.then((text) => {
expect(+text).equal(TEAMS.Customer_Support.users);
});
});
it('Assets tab should work properly', () => {
cy.intercept(
'/api/v1/search/query?q=*&from=0&size=*&sort_field=last_updated_timestamp&sort_order=desc&index=*'
).as('searchApi');
cy.get('[data-testid="Assets"]').should('be.visible').click();
cy.get('[data-testid="Assets"]').should('have.class', 'active');
cy.get('[data-testid="Assets"] > .tw-py-px > [data-testid="filter-count"]')
.invoke('text')
.then((text) => {
expect(+text).equal(0);
});
cy.contains('Your team does not have any dataset').should('be.visible');
cy.get('a > .button-comp').should('be.visible').contains('Explore');
searchEntity(SEARCH_ENTITY_TABLE.table_1.term);
cy.intercept(
'/api/v1/search/query?q=*&from=0&size=10&sort_order=desc&index=*'
).as('searchApi');
cy.wait('@searchApi');
cy.get('[data-testid="table-link"]')
.first()
.contains(SEARCH_ENTITY_TABLE.table_1.term)
.click();
cy.get('[data-testid="Manage"]').should('be.visible').click();
cy.get('[data-testid="owner-dropdown"]').should('be.visible').click();
cy.get('[data-testid="searchInputText"]')
.should('be.visible')
.type(TEAMS.Cloud_Infra.name);
cy.get('[data-testid="list-item"] > .tw-truncate')
.should('be.visible')
.click();
cy.clickOnLogo();
cy.get('[data-testid="terms"]').should('be.visible').click();
cy.get('[data-testid="Assets"]').should('be.visible').click();
cy.get('[data-testid="Assets"]').should('have.class', 'active');
cy.get('[data-testid="Assets"] > .tw-py-px > [data-testid="filter-count"]')
.invoke('text')
.then((text) => {
expect(+text).equal(1);
});
});
it('Roles tab should work properly', () => {
cy.intercept('/api/v1/teams?fields=*').as('teamApi');
cy.get('[data-testid="Roles"]').should('be.visible').click();
cy.get('[data-testid="Roles"]').should('have.class', 'active');
cy.get('[data-testid="Roles"] > .tw-py-px > [data-testid="filter-count"]')
.invoke('text')
.then((text) => {
expect(+text).equal(0);
});
cy.contains('There are no roles assigned yet.').should('be.visible');
cy.get(
'.tw-ml-5 > [data-testid="dropdown-item"] > div > [data-testid="menu-button"]'
)
.should('be.visible')
.click();
cy.get('[data-testid="menu-item-Roles"] > .tw-flex')
.should('be.visible')
.click();
cy.get('[data-testid="teams"]').should('be.visible').click();
cy.get('[data-testid="teams"]').should('have.class', 'active');
cy.get('[data-testid="add-teams-button"]').should('be.visible').click();
cy.get('.tw-modal-container').should('be.visible');
cy.get('[data-testid="checkboxAddUser"]')
.first()
.should('be.visible')
.click();
cy.get('[data-testid="AddUserSave"]').should('be.visible').click();
cy.clickOnLogo();
cy.get('[data-testid="terms"]').should('be.visible').click();
cy.get('[data-testid="Roles"]').should('be.visible').click();
cy.get('[data-testid="Roles"]').should('have.class', 'active');
cy.wait('@teamApi');
cy.get('[data-testid="Roles"] > .tw-py-px > [data-testid="filter-count"]')
.invoke('text')
.then((text) => {
expect(+text).equal(1);
});
});
it('Add owner flow should work properly', () => {
cy.get('[data-testid="Manage"]').should('be.visible').click();
cy.get('[data-testid="Manage"]').should('have.class', 'active');
cy.get(
'[data-testid="dropdown-profile"] > [data-testid="dropdown-item"] > :nth-child(1) > [data-testid="menu-button"]'
)
.should('be.visible')
.click();
cy.get('[data-testid="greeting-text"] > a > :nth-child(1)')
.should('be.visible')
.invoke('text')
.then((name) => {
cy.get('.tw-z-10').click();
cy.get('[data-testid="owner-dropdown"]').should('be.visible').click();
cy.get('[data-testid="searchInputText"]').type(name);
cy.get('[data-testid="list-item"]').should('be.visible').click();
cy.get('[data-testid="owner-dropdown"] > .tw-truncate')
.invoke('text')
.then((text) => {
expect(text).equal(name);
});
cy.get('[data-testid="owner-name"]')
.should('be.visible')
.contains(name);
});
});
it('Create new user should work properly', () => {
cy.get('[data-testid="users"] > .tw-group > [data-testid="user-type"]')
.should('be.visible')
.click();
cy.get('[data-testid="users"] > .tw-group').should(
'have.class',
'activeCategory'
);
cy.get('[data-testid="add-user-button"]').should('be.visible').click();
cy.contains('Create User').should('be.visible');
cy.get('[data-testid="email"]').should('be.visible').type(NEW_USER.email);
cy.get('[data-testid="displayName"]')
.should('be.visible')
.type(NEW_USER.display_name);
cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror')
.should('be.visible')
.type(NEW_USER.description);
cy.get(
':nth-child(5) > [data-testid="dropdown-item"] > div > [data-testid="menu-button"]'
)
.should('be.visible')
.click();
cy.get('[data-testid="Cloud_Infra"]').should('be.visible').click();
cy.get('[data-testid="close-dropdown"]').click();
cy.get(
':nth-child(6) > [data-testid="dropdown-item"] > div > [data-testid="menu-button"]'
)
.should('be.visible')
.click();
cy.get('[data-testid="Data Consumer"]').should('be.visible').click();
cy.get('[data-testid="close-dropdown"]').click();
cy.get('[data-testid="save-user"]').should('be.visible').click();
cy.get('[data-testid="searchbar"]')
.should('be.visible')
.type(NEW_USER.display_name);
cy.wait(500);
cy.get('[data-testid="user-card-container"]')
.first()
.contains(NEW_USER.display_name)
.should('exist')
.click();
cy.contains(NEW_USER.display_name).should('exist');
cy.contains(NEW_USER.description).should('exist');
cy.contains(NEW_USER.email).should('exist');
});
it('Delete user should work properly', () => {
cy.get('[data-testid="users"] > .tw-group > [data-testid="user-type"]')
.should('be.visible')
.click();
cy.get('[data-testid="users"] > .tw-group').should(
'have.class',
'activeCategory'
);
cy.get('[data-testid="searchbar"]')
.should('be.visible')
.type(NEW_USER.display_name);
cy.wait(500);
cy.get('[data-testid="user-card-container"]')
.first()
.contains(NEW_USER.display_name)
.should('exist');
cy.get('[data-testid="remove"] > [data-testid="image"]')
.should('not.be.visible')
.click();
cy.get('.tw-modal-container').should('be.visible');
cy.contains('Are you sure you want to delete').should('be.visible');
cy.get('[data-testid="save-button"]').should('be.visible').click();
cy.get('[data-testid="searchbar"]')
.should('be.visible')
.type(NEW_USER.display_name);
cy.wait(500);
cy.get('[data-testid="no-data-image"]').should('be.visible');
cy.contains('No user available').should('be.visible');
});
});

View File

@ -319,7 +319,7 @@ const TeamDetails = ({
title={TITLE_FOR_NON_ADMIN_ACTION}>
<Button
className="tw-h-8 tw-px-2"
data-testid="add-teams"
data-testid="add-user"
size="small"
theme="primary"
variant="contained"
@ -349,6 +349,7 @@ const TeamDetails = ({
<p>Would like to start adding some?</p>
<Button
className="tw-h-8 tw-rounded tw-my-2"
data-testid="add-new-user"
size="small"
theme="primary"
variant="contained"
@ -362,7 +363,7 @@ const TeamDetails = ({
<Fragment>
<div
className="tw-grid xxl:tw-grid-cols-4 lg:tw-grid-cols-3 md:tw-grid-cols-2 tw-gap-4"
data-testid="user-card-container">
data-testid="user-data-container">
{sortedUser.map((user, index) => {
const User = {
displayName: user.displayName || user.name,
@ -467,7 +468,7 @@ const TeamDetails = ({
) : (
<Button
className="tw-h-8 tw-rounded tw-ml-2"
data-testid="delete-team-button"
data-testid="leave-team-button"
size="small"
theme="primary"
variant="outlined"
@ -549,7 +550,7 @@ const TeamDetails = ({
</div>
) : (
<div className="tw-flex tw-group">
<span>{heading}</span>
<span data-testid="team-heading">{heading}</span>
{isActionAllowed() && (
<div className={classNames('tw-w-5 tw-min-w-max')}>
<NonAdminAction

View File

@ -87,7 +87,9 @@ const TeamsAndUsers = ({
return (
<>
<div className="tw-mb-8">
<div className="tw-flex tw-justify-between tw-items-center tw-mb-2 tw-border-b">
<div
className="tw-flex tw-justify-between tw-items-center tw-mb-2 tw-border-b"
data-testid="add-team-container">
<p className="tw-heading">Teams</p>
{hasAccess && (
<NonAdminAction
@ -95,7 +97,7 @@ const TeamsAndUsers = ({
title={TITLE_FOR_NON_ADMIN_ACTION}>
<Button
className="tw-h-7 tw-px-2 tw-mb-4"
data-testid="add-teams"
data-testid="add-team-button"
size="small"
theme="primary"
variant="contained"
@ -110,6 +112,7 @@ const TeamsAndUsers = ({
{teams.map((team) => (
<div
className="tw-flex tw-items-center tw-justify-between tw-mb-2 tw-cursor-pointer"
data-testid={`team-${team.name}`}
key={team.name}
onClick={() => {
changeCurrentTeam(team.name, false);
@ -121,6 +124,7 @@ const TeamsAndUsers = ({
)}`}>
<p
className="tag-category label-category tw-self-center tw-truncate tw-w-52"
data-testid="team-name"
title={team.displayName ?? team.name}>
{team.displayName ?? team.name}
</p>
@ -143,7 +147,7 @@ const TeamsAndUsers = ({
title={TITLE_FOR_NON_ADMIN_ACTION}>
<Button
className="tw-h-7 tw-px-2 tw-mb-4"
data-testid="add-teams"
data-testid="add-user-button"
size="small"
theme="primary"
variant="contained"
@ -156,6 +160,7 @@ const TeamsAndUsers = ({
{usersData.map((d) => (
<div
className="tw-flex tw-items-center tw-justify-between tw-mb-2 tw-cursor-pointer"
data-testid={d.name}
key={d.name}
onClick={() => {
changeCurrentTeam(d.name, true);
@ -167,6 +172,7 @@ const TeamsAndUsers = ({
)}`}>
<p
className="tag-category label-category tw-self-center tw-truncate tw-w-52"
data-testid="user-type"
title={capitalize(d.name)}>
{capitalize(d.name)}
</p>

View File

@ -104,7 +104,7 @@ const UserDetails = ({
{selectedUserList.length > 0 ? (
<div
className="tw-grid xxl:tw-grid-cols-3 lg:tw-grid-cols-2 tw-gap-4"
data-testid="user-card-container">
data-testid="user-container">
{selectedUserList.map((user, index) => {
const User = {
displayName: getEntityName(user as unknown as EntityReference),

View File

@ -12,6 +12,7 @@
*/
import { AxiosError, AxiosResponse } from 'axios';
import { startCase } from 'lodash';
import React, { Fragment, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { deleteEntity } from '../../../axiosAPIs/miscAPI';
@ -83,6 +84,10 @@ const DeleteWidget = ({
}
};
const getMessage = (message: string) => {
return message.replace('Entity', startCase(entityType));
};
const handleOnEntityDeleteConfirm = () => {
setEntityDeleteState((prev) => ({ ...prev, loading: 'waiting' }));
deleteEntity(
@ -96,7 +101,9 @@ const DeleteWidget = ({
setTimeout(() => {
handleOnEntityDeleteCancel();
showSuccessToast(
jsonData['api-success-messages']['delete-entity-success']
getMessage(
jsonData['api-success-messages']['delete-entity-success']
)
);
if (afterDeleteAction) {
afterDeleteAction();
@ -149,7 +156,7 @@ const DeleteWidget = ({
<div className="tw-mt-1 tw-bg-white" data-testid="danger-zone-container">
<div className="tw-border tw-border-error-70 tw-rounded tw-mt-3">
{allowSoftDelete && (
<div className="tw-border-b">
<div className="tw-border-b" data-testid="soft-delete">
<DeleteWidgetBody
buttonText="Soft delete"
description={prepareDeleteMessage(true)}
@ -160,15 +167,16 @@ const DeleteWidget = ({
/>
</div>
)}
<DeleteWidgetBody
buttonText="Delete"
description={prepareDeleteMessage()}
hasPermission={hasPermission}
header={`Delete ${getTitleCase(entityType)} ${entityName}`}
isOwner={isAdminUser}
onClick={() => handleOnEntityDelete(false)}
/>
<div data-testid="hard-delete">
<DeleteWidgetBody
buttonText="Delete"
description={prepareDeleteMessage()}
hasPermission={hasPermission}
header={`Delete ${getTitleCase(entityType)} ${entityName}`}
isOwner={isAdminUser}
onClick={() => handleOnEntityDelete(false)}
/>
</div>
</div>
</div>
{getDeleteModal()}

View File

@ -461,6 +461,7 @@ export const getInfoElements = (data: ExtraInfo) => {
'tw-mr-1 tw-inline-block tw-truncate tw-align-middle',
{ 'tw-w-52': (displayVal as string).length > 32 }
)}
data-testid="owner-name"
title={displayVal as string}>
{displayVal}
</span>