Fixed: Flaky cypress tests (#8017)

* Fixed: Flaky cypress tests

* fixed flaky pipeline related test

* miner fix at profiling side

* fixed cypress for description update

* glossary: fixed click is not getting register
This commit is contained in:
Shailesh Parmar 2022-10-08 00:07:24 +05:30 committed by GitHub
parent e25810e4aa
commit e141ab29db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 117 additions and 56 deletions

View File

@ -13,9 +13,12 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
import { SEARCH_INDEX } from '../constants/constants';
export const descriptionBox = export const descriptionBox =
'.toastui-editor-md-container > .toastui-editor > .ProseMirror'; '.toastui-editor-md-container > .toastui-editor > .ProseMirror';
export const uuid = () => Cypress._.random(0, 1e6); export const uuid = () => Cypress._.random(0, 1e6);
const RETRY_TIMES = 30;
const ADMIN = 'admin'; const ADMIN = 'admin';
@ -49,7 +52,7 @@ export const handleIngestionRetry = (
) => { ) => {
const rowIndex = ingestionType === 'metadata' ? 1 : 2; const rowIndex = ingestionType === 'metadata' ? 1 : 2;
// ingestions page // ingestions page
const retryTimes = 30;
let retryCount = count; let retryCount = count;
const testIngestionsTab = () => { const testIngestionsTab = () => {
cy.get('[data-testid="Ingestions"]').should('be.visible'); cy.get('[data-testid="Ingestions"]').should('be.visible');
@ -74,7 +77,7 @@ export const handleIngestionRetry = (
if ( if (
($ingestionStatus.text() === 'Running' || ($ingestionStatus.text() === 'Running' ||
$ingestionStatus.text() === 'Queued') && $ingestionStatus.text() === 'Queued') &&
retryCount <= retryTimes retryCount <= RETRY_TIMES
) { ) {
// retry after waiting for 20 seconds // retry after waiting for 20 seconds
cy.wait(20000); cy.wait(20000);
@ -403,12 +406,23 @@ export const searchEntity = (term, suggestionOverly = true) => {
export const visitEntityDetailsPage = (term, serviceName, entity) => { export const visitEntityDetailsPage = (term, serviceName, entity) => {
interceptURL('GET', '/api/v1/*/name/*', 'getEntityDetails'); interceptURL('GET', '/api/v1/*/name/*', 'getEntityDetails');
interceptURL('GET', '/api/v1/search/*', 'explorePageSearch'); interceptURL(
'GET',
`/api/v1/search/query?q=*&from=*&size=*&index=${SEARCH_INDEX[entity]}`,
'explorePageTabSearch'
);
interceptURL(
'GET',
`/api/v1/search/suggest?q=*&index=dashboard_search_index,table_search_index,topic_search_index,pipeline_search_index,mlmodel_search_index`,
'searchQuery'
);
interceptURL('GET', `/api/v1/search/*`, 'explorePageSearch');
// searching term in search box // searching term in search box
cy.get('[data-testid="searchBox"]').scrollIntoView().should('be.visible'); cy.get('[data-testid="searchBox"]').scrollIntoView().should('be.visible');
cy.get('[data-testid="searchBox"]').type(term); cy.get('[data-testid="searchBox"]').type(term);
cy.get('[data-testid="suggestion-overlay"]').should('exist'); cy.get('[data-testid="suggestion-overlay"]').should('exist');
verifyResponseStatusCode('@searchQuery', 200);
cy.get('body').then(($body) => { cy.get('body').then(($body) => {
// checking if requested term is available in search suggestion // checking if requested term is available in search suggestion
if ( if (
@ -425,12 +439,13 @@ export const visitEntityDetailsPage = (term, serviceName, entity) => {
// if term is not available in search suggestion, hitting enter to search box so it will redirect to explore page // if term is not available in search suggestion, hitting enter to search box so it will redirect to explore page
cy.get('body').click(1, 1); cy.get('body').click(1, 1);
cy.get('[data-testid="searchBox"]').type('{enter}'); cy.get('[data-testid="searchBox"]').type('{enter}');
verifyResponseStatusCode('@explorePageSearch', 200);
cy.get(`[data-testid="${entity}-tab"]`).should('be.visible').click(); cy.get(`[data-testid="${entity}-tab"]`).should('be.visible').click();
cy.get(`[data-testid="${entity}-tab"]`) cy.get(`[data-testid="${entity}-tab"]`)
.should('be.visible') .should('be.visible')
.should('have.class', 'active'); .should('have.class', 'active');
verifyResponseStatusCode('@explorePageSearch', 200); verifyResponseStatusCode('@explorePageTabSearch', 200);
cy.get(`[data-testid="${serviceName}-${term}"]`) cy.get(`[data-testid="${serviceName}-${term}"]`)
.scrollIntoView() .scrollIntoView()
@ -811,7 +826,9 @@ export const deleteCreatedProperty = (propertyName) => {
cy.get('[data-testid="save-button"]').should('be.visible').click(); cy.get('[data-testid="save-button"]').should('be.visible').click();
//Checking if property got deleted successfully //Checking if property got deleted successfully
cy.get('[data-testid="add-field-button"]').scrollIntoView().should('be.visible'); cy.get('[data-testid="add-field-button"]')
.scrollIntoView()
.should('be.visible');
}; };
export const updateOwner = () => { export const updateOwner = () => {
@ -911,7 +928,6 @@ export const addTeam = (TEAM_DETAILS) => {
}; };
export const retryIngestionRun = () => { export const retryIngestionRun = () => {
const retryTimes = 10;
let retryCount = 0; let retryCount = 0;
const testIngestionsTab = () => { const testIngestionsTab = () => {
@ -935,7 +951,7 @@ export const retryIngestionRun = () => {
if ( if (
($ingestionStatus.text() === 'Running' || ($ingestionStatus.text() === 'Running' ||
$ingestionStatus.text() === 'Queued') && $ingestionStatus.text() === 'Queued') &&
retryCount <= retryTimes retryCount <= RETRY_TIMES
) { ) {
// retry after waiting for 20 seconds // retry after waiting for 20 seconds
cy.wait(20000); cy.wait(20000);

View File

@ -11,8 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { uuid } from '../common/common'; export const uuid = () => Cypress._.random(0, 1e6);
const id = uuid(); const id = uuid();
export const MYDATA_SUMMARY_OPTIONS = { export const MYDATA_SUMMARY_OPTIONS = {
@ -23,7 +22,15 @@ export const MYDATA_SUMMARY_OPTIONS = {
service: 'service', service: 'service',
user: 'user', user: 'user',
terms: 'terms', terms: 'terms',
mlmodels:'mlmodels' mlmodels: 'mlmodels',
};
export const SEARCH_INDEX = {
tables: 'table_search_index',
topics: 'topic_search_index',
dashboards: 'dashboard_search_index',
pipelines: 'pipeline_search_index',
mlmodels: 'mlmodel_search_index',
}; };
export const SEARCH_ENTITY_TABLE = { export const SEARCH_ENTITY_TABLE = {

View File

@ -83,6 +83,7 @@ describe('Data Quality and Profiler should work properly', () => {
.scrollIntoView() .scrollIntoView()
.contains('Profiler Ingestion') .contains('Profiler Ingestion')
.click(); .click();
cy.get('[data-testid="profileSample"]').should('be.visible').type(0.01);
cy.get('[data-testid="next-button"]') cy.get('[data-testid="next-button"]')
.scrollIntoView() .scrollIntoView()
.should('be.visible') .should('be.visible')
@ -107,7 +108,7 @@ describe('Data Quality and Profiler should work properly', () => {
cy.goToHomePage(); cy.goToHomePage();
goToProfilerTab(); goToProfilerTab();
cy.get('[data-testid="no-profiler-placeholder"]').should('not.exist'); cy.get('[data-testid="no-profiler-placeholder"]').should('not.exist');
}) });
it('Add table test case with new test suite', () => { it('Add table test case with new test suite', () => {
login(LOGIN.username, LOGIN.password); login(LOGIN.username, LOGIN.password);

View File

@ -325,7 +325,7 @@ describe('Glossary page should work properly', () => {
cy.get('[data-testid="section-related-terms"] [data-testid="edit-button"]') cy.get('[data-testid="section-related-terms"] [data-testid="edit-button"]')
.scrollIntoView() .scrollIntoView()
.should('be.visible') .should('be.visible')
.click(); .click({ force: true });
interceptURL( interceptURL(
'GET', 'GET',
'/api/v1/search/query?q=*&from=0&size=10&index=glossary_search_index', '/api/v1/search/query?q=*&from=0&size=10&index=glossary_search_index',

View File

@ -24,7 +24,7 @@ const invalidPassword = 'testUsers@123';
const baseURL = location.origin; const baseURL = location.origin;
const ERROR_MESSAGE = 'You have entered an invalid username or password.' const ERROR_MESSAGE = 'You have entered an invalid username or password.';
describe('Login flow should work properly', () => { describe('Login flow should work properly', () => {
it('Signup and Login with signed up credentials', () => { it('Signup and Login with signed up credentials', () => {
@ -57,9 +57,7 @@ describe('Login flow should work properly', () => {
.type(CREDENTIALS.password); .type(CREDENTIALS.password);
//Click on create account button //Click on create account button
cy.get('.ant-btn').contains('Create Account').should('be.visible').click(); cy.get('.ant-btn').contains('Create Account').should('be.visible').click();
cy.url() cy.url().should('eq', `${baseURL}/signin`).and('contain', 'signin');
.should('eq', `${baseURL}/signin`)
.and('contain', 'signin');
//Login with the created user //Login with the created user
@ -75,7 +73,9 @@ describe('Login flow should work properly', () => {
.invoke('text') .invoke('text')
.should('contain', `${CREDENTIALS.firstName}${CREDENTIALS.lastName}`); .should('contain', `${CREDENTIALS.firstName}${CREDENTIALS.lastName}`);
interceptURL('GET', 'api/v1/users/name/*', 'getUserPage'); interceptURL('GET', 'api/v1/users/name/*', 'getUserPage');
cy.get('[data-testid="user-name"]').should('be.visible').click({force: true}); cy.get('[data-testid="user-name"]')
.should('be.visible')
.click({ force: true });
verifyResponseStatusCode('@getUserPage', 200); verifyResponseStatusCode('@getUserPage', 200);
cy.get('[data-testid="left-panel"]').should( cy.get('[data-testid="left-panel"]').should(
'contain', 'contain',
@ -104,7 +104,11 @@ describe('Login flow should work properly', () => {
cy.visit('/'); cy.visit('/');
verifyResponseStatusCode('@getLoginPage', 200); verifyResponseStatusCode('@getLoginPage', 200);
//Click on Forgot button //Click on Forgot button
cy.get('[data-testid="forgot-password"]').should('be.visible').click(); cy.get('[data-testid="forgot-password"]')
.should('be.visible')
.trigger('mouseover')
.click();
cy.url() cy.url()
.should('eq', `${baseURL}/forgot-password`) .should('eq', `${baseURL}/forgot-password`)
.and('contain', 'forgot-password'); .and('contain', 'forgot-password');

View File

@ -26,6 +26,13 @@ const TEAM_DETAILS = {
ownername: 'Aaron Johnson', ownername: 'Aaron Johnson',
assetname: 'dim_address', assetname: 'dim_address',
}; };
const hardDeleteTeamName = `team-ct-test-${uuid()}`;
const HARD_DELETE_TEAM_DETAILS = {
name: hardDeleteTeamName,
displayName: hardDeleteTeamName,
teamType: 'Department',
description: `This is ${hardDeleteTeamName} description`,
};
describe('Teams flow should work properly', () => { describe('Teams flow should work properly', () => {
before(() => { before(() => {
@ -35,6 +42,7 @@ describe('Teams flow should work properly', () => {
cy.saveLocalStorage('localstorage'); cy.saveLocalStorage('localstorage');
}); });
beforeEach(() => { beforeEach(() => {
interceptURL('GET', `/api/v1/users?fields=*`, 'getUserDetails');
cy.log('Restoring local storage snapshot'); cy.log('Restoring local storage snapshot');
cy.restoreLocalStorage('localstorage'); cy.restoreLocalStorage('localstorage');
cy.clickOnLogo(); cy.clickOnLogo();
@ -73,6 +81,9 @@ describe('Teams flow should work properly', () => {
cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click(); cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click();
verifyResponseStatusCode('@getUsers', 200); verifyResponseStatusCode('@getUsers', 200);
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.contains(TEAM_DETAILS.name);
//Clicking on users tab //Clicking on users tab
cy.get('[data-testid="Users"]') cy.get('[data-testid="Users"]')
.should('exist') .should('exist')
@ -158,16 +169,18 @@ describe('Teams flow should work properly', () => {
cy.get('body').find('[data-testid="leave-team-button"]').should('exist'); cy.get('body').find('[data-testid="leave-team-button"]').should('exist');
}); });
it('Update description and display name for created team', () => { it('Update display name for created team', () => {
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/teams/name/${TEAM_DETAILS.name}*`, `/api/v1/teams/name/${TEAM_DETAILS.name}*`,
'getSelectedTeam' 'getSelectedTeam'
); );
interceptURL('PATCH', `/api/v1/teams/*`, 'patchTeam');
//Click on created team name //Click on created team name
cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click(); cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click();
verifyResponseStatusCode('@getSelectedTeam', 200); verifyResponseStatusCode('@getSelectedTeam', 200);
verifyResponseStatusCode('@getUserDetails', 200);
//Click on edit display name //Click on edit display name
cy.get('[data-testid="edit-synonyms"]').should('be.visible').click(); cy.get('[data-testid="edit-synonyms"]').should('be.visible').click();
@ -178,18 +191,37 @@ describe('Teams flow should work properly', () => {
.clear() .clear()
.type(TEAM_DETAILS.updatedname); .type(TEAM_DETAILS.updatedname);
interceptURL(
'GET',
`api/v1/users?fields=teams,roles&team=${TEAM_DETAILS.name}&limit=15`,
'getTeamDetails'
);
//Save the updated display name //Save the updated display name
cy.get('[data-testid="saveAssociatedTag"]') cy.get('[data-testid="saveAssociatedTag"]')
.should('exist') .should('exist')
.should('be.visible') .should('be.visible')
.click(); .click();
verifyResponseStatusCode('@getTeamDetails', 200); verifyResponseStatusCode('@patchTeam', 200);
verifyResponseStatusCode('@getSelectedTeam', 200);
verifyResponseStatusCode('@getUserDetails', 200);
//Validate the updated display name
cy.get('[data-testid="team-heading"]').then(($el) => {
cy.wrap($el).should('have.text', TEAM_DETAILS.updatedname);
});
cy.get('[data-testid="inactive-link"]')
.should('be.visible')
.should('contain', TEAM_DETAILS.updatedname);
});
it('Update description for created team', () => {
interceptURL('GET', `/api/v1/teams/name/*`, 'getSelectedTeam');
interceptURL('PATCH', `/api/v1/teams/*`, 'patchTeam');
//Click on created team name
cy.get('table')
.find('.ant-table-row')
.contains(TEAM_DETAILS.updatedname)
.click();
verifyResponseStatusCode('@getSelectedTeam', 200);
verifyResponseStatusCode('@getUserDetails', 200);
//Validate the updated display name //Validate the updated display name
cy.get('[data-testid="team-heading"]').then(($el) => { cy.get('[data-testid="team-heading"]').then(($el) => {
cy.wrap($el).should('have.text', TEAM_DETAILS.updatedname); cy.wrap($el).should('have.text', TEAM_DETAILS.updatedname);
@ -201,10 +233,8 @@ describe('Teams flow should work properly', () => {
//Click on edit description button //Click on edit description button
cy.get('[data-testid="edit-description"]') cy.get('[data-testid="edit-description"]')
.should('exist') .should('be.visible')
.then(($editDescription) => { .click({ force: true });
cy.wrap($editDescription).should('be.visible').click();
});
//Entering updated description //Entering updated description
cy.get(descriptionBox).clear().type(updateddescription); cy.get(descriptionBox).clear().type(updateddescription);
@ -286,6 +316,10 @@ describe('Teams flow should work properly', () => {
cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click(); cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click();
verifyResponseStatusCode('@getSelectedTeam', 200); verifyResponseStatusCode('@getSelectedTeam', 200);
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.contains(TEAM_DETAILS.name);
verifyResponseStatusCode('@getUserDetails', 200);
// //Click on Leave team // //Click on Leave team
cy.get('[data-testid="leave-team-button"]').should('be.visible').click(); cy.get('[data-testid="leave-team-button"]').should('be.visible').click();
@ -308,7 +342,10 @@ describe('Teams flow should work properly', () => {
cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click(); cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click();
verifyResponseStatusCode('@getSelectedTeam', 200); verifyResponseStatusCode('@getSelectedTeam', 200);
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.contains(TEAM_DETAILS.updatedname);
verifyResponseStatusCode('@getUserDetails', 200);
cy.get('[data-testid="manage-button"]') cy.get('[data-testid="manage-button"]')
.should('exist') .should('exist')
.should('be.visible') .should('be.visible')
@ -325,23 +362,6 @@ describe('Teams flow should work properly', () => {
.should('exist') .should('exist')
.should('be.disabled'); .should('be.disabled');
cy.get('[data-testid="discard-button"]')
.should('exist')
.should('be.visible')
.click();
cy.get('[data-testid="manage-button"]')
.should('exist')
.should('be.visible')
.click();
cy.get('[data-menu-id*="delete-button"]').should('be.visible');
cy.get('[data-testid="delete-button-title"]')
.should('exist')
.should('be.visible')
.click();
//Click on soft delete option //Click on soft delete option
cy.get('[data-testid="soft-delete-option"]') cy.get('[data-testid="soft-delete-option"]')
.should('contain', TEAM_DETAILS.name) .should('contain', TEAM_DETAILS.name)
@ -378,6 +398,10 @@ describe('Teams flow should work properly', () => {
cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click(); cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click();
verifyResponseStatusCode('@getSelectedTeam', 200); verifyResponseStatusCode('@getSelectedTeam', 200);
cy.get('[data-testid="team-heading"]')
.should('be.visible')
.contains(TEAM_DETAILS.updatedname);
verifyResponseStatusCode('@getUserDetails', 200);
cy.get('[data-testid="manage-button"]') cy.get('[data-testid="manage-button"]')
.should('exist') .should('exist')
@ -420,18 +444,21 @@ describe('Teams flow should work properly', () => {
it('Permanently deleting a team without soft deleting should work properly', () => { it('Permanently deleting a team without soft deleting should work properly', () => {
//Add a new team //Add a new team
addTeam(TEAM_DETAILS); addTeam(HARD_DELETE_TEAM_DETAILS);
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/teams/name/${TEAM_DETAILS.name}*`, `/api/v1/teams/name/${HARD_DELETE_TEAM_DETAILS.name}*`,
'getSelectedTeam' 'getSelectedTeam'
); );
//Click on created team //Click on created team
cy.get('table').find('.ant-table-row').contains(TEAM_DETAILS.name).click(); cy.get('table')
.find('.ant-table-row')
.contains(HARD_DELETE_TEAM_DETAILS.name)
.click();
verifyResponseStatusCode('@getSelectedTeam', 200); verifyResponseStatusCode('@getSelectedTeam', 200);
verifyResponseStatusCode('@getUserDetails', 200);
cy.get('[data-testid="manage-button"]') cy.get('[data-testid="manage-button"]')
.should('exist') .should('exist')
.should('be.visible') .should('be.visible')
@ -450,12 +477,12 @@ describe('Teams flow should work properly', () => {
//Check if soft delete option is present //Check if soft delete option is present
cy.get('[data-testid="soft-delete-option"]') cy.get('[data-testid="soft-delete-option"]')
.should('contain', TEAM_DETAILS.name) .should('contain', HARD_DELETE_TEAM_DETAILS.name)
.should('be.visible'); .should('be.visible');
//Click on permanent delete option //Click on permanent delete option
cy.get('[data-testid="hard-delete-option"]') cy.get('[data-testid="hard-delete-option"]')
.should('contain', TEAM_DETAILS.name) .should('contain', HARD_DELETE_TEAM_DETAILS.name)
.should('be.visible') .should('be.visible')
.click(); .click();
@ -474,6 +501,6 @@ describe('Teams flow should work properly', () => {
//Validating the deleted team //Validating the deleted team
cy.get('table').should('not.contain', TEAM_DETAILS.name); cy.get('table').should('not.contain', HARD_DELETE_TEAM_DETAILS.name);
}); });
}); });

View File

@ -38,6 +38,7 @@ import {
getEntityId, getEntityId,
getEntityName, getEntityName,
getEntityPlaceHolder, getEntityPlaceHolder,
getNameFromFQN,
getOwnerValue, getOwnerValue,
getPartialNameFromTableFQN, getPartialNameFromTableFQN,
} from '../../../utils/CommonUtils'; } from '../../../utils/CommonUtils';
@ -161,7 +162,7 @@ const TableDataCard: FunctionComponent<Props> = ({
className="tw-text-grey-body tw-font-semibold" className="tw-text-grey-body tw-font-semibold"
data-testid={`${getPartialNameFromTableFQN(fullyQualifiedName, [ data-testid={`${getPartialNameFromTableFQN(fullyQualifiedName, [
FqnPart.Service, FqnPart.Service,
])}-${getPartialNameFromTableFQN(fullyQualifiedName, [FqnPart.Table])}`} ])}-${getNameFromFQN(fullyQualifiedName)}`}
id={`${id}Title`} id={`${id}Title`}
onClick={handleLinkClick}> onClick={handleLinkClick}>
{stringToHTML(name)} {stringToHTML(name)}

View File

@ -64,6 +64,7 @@ const TeamsPage = () => {
const { isAdminUser } = useAuth(); const { isAdminUser } = useAuth();
const { isAuthDisabled } = useAuthContext(); const { isAuthDisabled } = useAuthContext();
const { fqn } = useParams<{ [key: string]: string }>(); const { fqn } = useParams<{ [key: string]: string }>();
const [currentFqn, setCurrentFqn] = useState<string>('');
const [allTeam, setAllTeam] = useState<Team[]>([]); const [allTeam, setAllTeam] = useState<Team[]>([]);
const [selectedTeam, setSelectedTeam] = useState<Team>({} as Team); const [selectedTeam, setSelectedTeam] = useState<Team>({} as Team);
const [users, setUsers] = useState<User[]>([]); const [users, setUsers] = useState<User[]>([]);
@ -470,11 +471,15 @@ const TeamsPage = () => {
}; };
useEffect(() => { useEffect(() => {
if (entityPermissions.ViewAll || entityPermissions.ViewBasic) { if (
(entityPermissions.ViewAll || entityPermissions.ViewBasic) &&
currentFqn !== fqn
) {
if (fqn) { if (fqn) {
fetchTeamByFqn(fqn); fetchTeamByFqn(fqn);
} }
fetchAllTeams(false, fqn); fetchAllTeams(false, fqn);
setCurrentFqn(fqn);
} }
}, [entityPermissions, fqn]); }, [entityPermissions, fqn]);