mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-31 02:29:03 +00:00 
			
		
		
		
	playwright: migrate incident manager test to playwright (#17657)
* playwright: migrate incident manager test to playwright * migrate remaining test to playwright * added serial mode to prevent load while deploying pipeline
This commit is contained in:
		
							parent
							
								
									53cc84aef1
								
							
						
					
					
						commit
						b9311526a7
					
				| @ -1,538 +0,0 @@ | ||||
| /* | ||||
|  *  Copyright 2024 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 { interceptURL, verifyResponseStatusCode } from '../../common/common'; | ||||
| import { triggerTestCasePipeline } from '../../common/Utils/DataQuality'; | ||||
| import { | ||||
|   createEntityTableViaREST, | ||||
|   deleteEntityViaREST, | ||||
|   visitEntityDetailsPage, | ||||
| } from '../../common/Utils/Entity'; | ||||
| import { getToken } from '../../common/Utils/LocalStorage'; | ||||
| import { generateRandomUser } from '../../common/Utils/Owner'; | ||||
| import { uuid } from '../../constants/constants'; | ||||
| import { EntityType, SidebarItem } from '../../constants/Entity.interface'; | ||||
| import { DATABASE_SERVICE } from '../../constants/EntityConstant'; | ||||
| const TABLE_NAME = DATABASE_SERVICE.entity.name; | ||||
| 
 | ||||
| const testSuite = { | ||||
|   name: `${DATABASE_SERVICE.entity.databaseSchema}.${DATABASE_SERVICE.entity.name}.testSuite`, | ||||
|   executableEntityReference: `${DATABASE_SERVICE.entity.databaseSchema}.${DATABASE_SERVICE.entity.name}`, | ||||
| }; | ||||
| 
 | ||||
| const testCases = [ | ||||
|   `cy_first_table_column_count_to_be_between_${uuid()}`, | ||||
|   `cy_second_table_column_count_to_be_between_${uuid()}`, | ||||
|   `cy_third_table_column_count_to_be_between_${uuid()}`, | ||||
| ]; | ||||
| const user1 = generateRandomUser(); | ||||
| const user2 = generateRandomUser(); | ||||
| const user3 = generateRandomUser(); | ||||
| const userData1 = { | ||||
|   displayName: `${user1.firstName}${user1.lastName}`, | ||||
|   name: user1.email.split('@')[0], | ||||
| }; | ||||
| const userData2 = { | ||||
|   displayName: `${user2.firstName}${user2.lastName}`, | ||||
|   name: user2.email.split('@')[0], | ||||
| }; | ||||
| const userData3 = { | ||||
|   displayName: `${user3.firstName}${user3.lastName}`, | ||||
|   name: user3.email.split('@')[0], | ||||
| }; | ||||
| const userIds: string[] = []; | ||||
| 
 | ||||
| const goToProfilerTab = () => { | ||||
|   interceptURL( | ||||
|     'GET', | ||||
|     `api/v1/tables/name/${DATABASE_SERVICE.service.name}.*.${TABLE_NAME}?fields=*&include=all`, | ||||
|     'waitForPageLoad' | ||||
|   ); | ||||
|   visitEntityDetailsPage({ | ||||
|     term: TABLE_NAME, | ||||
|     serviceName: DATABASE_SERVICE.service.name, | ||||
|     entity: EntityType.Table, | ||||
|   }); | ||||
|   verifyResponseStatusCode('@waitForPageLoad', 200); | ||||
| 
 | ||||
|   cy.get('[data-testid="profiler"]').should('be.visible').click(); | ||||
|   cy.get('[data-testid="profiler-tab-left-panel"]') | ||||
|     .contains('Table Profile') | ||||
|     .click(); | ||||
| }; | ||||
| 
 | ||||
| const acknowledgeTask = (testCase: string) => { | ||||
|   goToProfilerTab(); | ||||
| 
 | ||||
|   cy.get('[data-testid="profiler-tab-left-panel"]') | ||||
|     .contains('Data Quality') | ||||
|     .click(); | ||||
|   cy.get(`[data-testid="${testCase}"]`) | ||||
|     .find('.last-run-box.failed') | ||||
|     .scrollIntoView() | ||||
|     .should('be.visible'); | ||||
|   cy.get(`[data-testid="${testCase}-status"]`).should('contain', 'New'); | ||||
|   cy.get(`[data-testid="${testCase}"]`).contains(testCase).click(); | ||||
|   cy.get('[data-testid="edit-resolution-icon"]').click(); | ||||
|   cy.get('[data-testid="test-case-resolution-status-type"]').click(); | ||||
|   cy.get('[title="Ack"]').click(); | ||||
|   interceptURL( | ||||
|     'POST', | ||||
|     '/api/v1/dataQuality/testCases/testCaseIncidentStatus', | ||||
|     'updateTestCaseIncidentStatus' | ||||
|   ); | ||||
|   cy.get('#update-status-button').click(); | ||||
|   verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200); | ||||
|   cy.get(`[data-testid="${testCase}-status"]`).should('contain', 'Ack'); | ||||
| }; | ||||
| 
 | ||||
| const assignIncident = (testCaseName: string) => { | ||||
|   cy.sidebarClick(SidebarItem.INCIDENT_MANAGER); | ||||
|   cy.get(`[data-testid="test-case-${testCaseName}"]`).should('be.visible'); | ||||
|   cy.get(`[data-testid="${testCaseName}-status"]`) | ||||
|     .find(`[data-testid="edit-resolution-icon"]`) | ||||
|     .click(); | ||||
|   cy.get(`[data-testid="test-case-resolution-status-type"]`).click(); | ||||
|   cy.get(`[title="Assigned"]`).click(); | ||||
|   cy.get('#testCaseResolutionStatusDetails_assignee').should('be.visible'); | ||||
|   interceptURL( | ||||
|     'GET', | ||||
|     `/api/v1/search/suggest?q=*${user1.firstName}*${user1.lastName}*&index=user_search_index*`, | ||||
|     'searchAssignee' | ||||
|   ); | ||||
|   interceptURL('GET', '/api/v1/users/name/*', 'userList'); | ||||
|   cy.get('#testCaseResolutionStatusDetails_assignee').click(); | ||||
|   cy.wait('@userList'); | ||||
|   cy.get('#testCaseResolutionStatusDetails_assignee').type( | ||||
|     userData1.displayName | ||||
|   ); | ||||
|   verifyResponseStatusCode('@searchAssignee', 200); | ||||
|   cy.get(`[data-testid="${userData1.name.toLocaleLowerCase()}"]`).click(); | ||||
|   interceptURL( | ||||
|     'POST', | ||||
|     '/api/v1/dataQuality/testCases/testCaseIncidentStatus', | ||||
|     'updateTestCaseIncidentStatus' | ||||
|   ); | ||||
|   cy.get('#update-status-button').click(); | ||||
|   verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200); | ||||
|   cy.get( | ||||
|     `[data-testid="${testCaseName}-status"] [data-testid="badge-container"]` | ||||
|   ).should('contain', 'Assigned'); | ||||
| }; | ||||
| 
 | ||||
| describe('Incident Manager', { tags: 'Observability' }, () => { | ||||
|   before(() => { | ||||
|     cy.login(); | ||||
| 
 | ||||
|     cy.getAllLocalStorage().then((data) => { | ||||
|       const token = getToken(data); | ||||
| 
 | ||||
|       // Create a new user
 | ||||
|       for (const user of [user1, user2, user3]) { | ||||
|         cy.request({ | ||||
|           method: 'POST', | ||||
|           url: `/api/v1/users/signup`, | ||||
|           headers: { Authorization: `Bearer ${token}` }, | ||||
|           body: user, | ||||
|         }).then((response) => { | ||||
|           userIds.push(response.body.id); | ||||
|         }); | ||||
|       } | ||||
| 
 | ||||
|       createEntityTableViaREST({ | ||||
|         token, | ||||
|         ...DATABASE_SERVICE, | ||||
|         tables: [DATABASE_SERVICE.entity], | ||||
|       }); | ||||
|       // create testSuite
 | ||||
|       cy.request({ | ||||
|         method: 'POST', | ||||
|         url: `/api/v1/dataQuality/testSuites/executable`, | ||||
|         headers: { Authorization: `Bearer ${token}` }, | ||||
|         body: testSuite, | ||||
|       }).then((testSuiteResponse) => { | ||||
|         // creating test case
 | ||||
| 
 | ||||
|         testCases.forEach((testCase) => { | ||||
|           cy.request({ | ||||
|             method: 'POST', | ||||
|             url: `/api/v1/dataQuality/testCases`, | ||||
|             headers: { Authorization: `Bearer ${token}` }, | ||||
|             body: { | ||||
|               name: testCase, | ||||
|               entityLink: `<#E::table::${testSuite.executableEntityReference}>`, | ||||
|               parameterValues: [ | ||||
|                 { name: 'minColValue', value: 12 }, | ||||
|                 { name: 'maxColValue', value: 24 }, | ||||
|               ], | ||||
|               testDefinition: 'tableColumnCountToBeBetween', | ||||
|               testSuite: testSuite.name, | ||||
|             }, | ||||
|           }); | ||||
|         }); | ||||
|         cy.request({ | ||||
|           method: 'POST', | ||||
|           url: `/api/v1/services/ingestionPipelines`, | ||||
|           headers: { Authorization: `Bearer ${token}` }, | ||||
|           body: { | ||||
|             airflowConfig: {}, | ||||
|             name: `${testSuite.executableEntityReference}_test_suite`, | ||||
|             pipelineType: 'TestSuite', | ||||
|             service: { | ||||
|               id: testSuiteResponse.body.id, | ||||
|               type: 'testSuite', | ||||
|             }, | ||||
|             sourceConfig: { | ||||
|               config: { | ||||
|                 type: 'TestSuite', | ||||
|                 entityFullyQualifiedName: testSuite.executableEntityReference, | ||||
|               }, | ||||
|             }, | ||||
|           }, | ||||
|         }).then((response) => | ||||
|           cy.request({ | ||||
|             method: 'POST', | ||||
|             url: `/api/v1/services/ingestionPipelines/deploy/${response.body.id}`, | ||||
|             headers: { Authorization: `Bearer ${token}` }, | ||||
|           }) | ||||
|         ); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     triggerTestCasePipeline({ | ||||
|       serviceName: DATABASE_SERVICE.service.name, | ||||
|       tableName: TABLE_NAME, | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   after(() => { | ||||
|     cy.login(); | ||||
| 
 | ||||
|     cy.getAllLocalStorage().then((data) => { | ||||
|       const token = getToken(data); | ||||
|       deleteEntityViaREST({ | ||||
|         token, | ||||
|         endPoint: EntityType.DatabaseService, | ||||
|         entityName: DATABASE_SERVICE.service.name, | ||||
|       }); | ||||
| 
 | ||||
|       // Delete created user
 | ||||
|       userIds.forEach((userId) => { | ||||
|         cy.request({ | ||||
|           method: 'DELETE', | ||||
|           url: `/api/v1/users/${userId}?hardDelete=true&recursive=false`, | ||||
|           headers: { Authorization: `Bearer ${token}` }, | ||||
|         }); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('Basic Scenario', () => { | ||||
|     const testCaseName = testCases[0]; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       cy.login(); | ||||
|     }); | ||||
| 
 | ||||
|     it("Acknowledge table test case's failure", () => { | ||||
|       acknowledgeTask(testCaseName); | ||||
|     }); | ||||
| 
 | ||||
|     it('Assign incident to user', () => { | ||||
|       assignIncident(testCaseName); | ||||
|     }); | ||||
| 
 | ||||
|     it('Re-assign incident to user', () => { | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases/name/*?fields=*', | ||||
|         'getTestCase' | ||||
|       ); | ||||
|       interceptURL('GET', '/api/v1/feed?entityLink=*&type=Task', 'getTaskFeed'); | ||||
|       cy.sidebarClick(SidebarItem.INCIDENT_MANAGER); | ||||
|       cy.get(`[data-testid="test-case-${testCaseName}"]`).click(); | ||||
|       verifyResponseStatusCode('@getTestCase', 200); | ||||
|       cy.get('[data-testid="incident"]').click(); | ||||
|       verifyResponseStatusCode('@getTaskFeed', 200); | ||||
|       cy.get('[data-testid="task-cta-buttons"] [role="img"]') | ||||
|         .scrollIntoView() | ||||
|         .click(); | ||||
|       cy.get('[role="menu"').find('[data-menu-id*="re-assign"]').click(); | ||||
| 
 | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         `/api/v1/search/suggest?q=*${user2.firstName}*${user2.lastName}*&index=user_search_index*`, | ||||
|         'searchAssignee' | ||||
|       ); | ||||
|       interceptURL('GET', '/api/v1/users/name/*', 'userList'); | ||||
|       cy.get('[data-testid="select-assignee"]').click(); | ||||
|       cy.wait('@userList'); | ||||
|       cy.get('[data-testid="select-assignee"]').type(userData2.displayName); | ||||
|       verifyResponseStatusCode('@searchAssignee', 200); | ||||
|       cy.get(`[data-testid="${userData2.name.toLocaleLowerCase()}"]`).click(); | ||||
| 
 | ||||
|       interceptURL( | ||||
|         'POST', | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus', | ||||
|         'updateTestCaseIncidentStatus' | ||||
|       ); | ||||
|       cy.get('.ant-modal-footer').contains('Submit').click(); | ||||
|       verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200); | ||||
|       // Todo: skipping this for now as its not working from backend
 | ||||
|       cy.clickOnLogo(); | ||||
|       cy.get('[id*="tab-tasks"]').click(); | ||||
|       cy.get('[data-testid="task-feed-card"]') | ||||
|         .contains(testCaseName) | ||||
|         .scrollIntoView() | ||||
|         .should('be.visible'); | ||||
|     }); | ||||
| 
 | ||||
|     it("Re-assign incident from test case page's header", () => { | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases/name/*?fields=*', | ||||
|         'getTestCase' | ||||
|       ); | ||||
|       interceptURL('GET', '/api/v1/feed?entityLink=*&type=Task', 'getTaskFeed'); | ||||
|       cy.sidebarClick(SidebarItem.INCIDENT_MANAGER); | ||||
|       cy.get(`[data-testid="test-case-${testCaseName}"]`).click(); | ||||
|       verifyResponseStatusCode('@getTestCase', 200); | ||||
|       interceptURL('GET', '/api/v1/users?*', 'getUsers'); | ||||
|       cy.get('[data-testid="assignee"] [data-testid="edit-owner"]').click(); | ||||
|       verifyResponseStatusCode('@getUsers', 200); | ||||
|       cy.get('[data-testid="loader"]').should('not.exist'); | ||||
|       interceptURL('GET', `api/v1/search/query?q=*`, 'searchOwner'); | ||||
|       cy.get('[data-testid="owner-select-users-search-bar"]').type( | ||||
|         userData3.displayName | ||||
|       ); | ||||
|       verifyResponseStatusCode('@searchOwner', 200); | ||||
|       interceptURL( | ||||
|         'POST', | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus', | ||||
|         'updateTestCaseIncidentStatus' | ||||
|       ); | ||||
|       cy.get(`.ant-popover [title="${userData3.displayName}"]`).click(); | ||||
|       verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200); | ||||
|       cy.get('[data-testid="assignee"] [data-testid="owner-link"]').should( | ||||
|         'contain', | ||||
|         userData3.displayName | ||||
|       ); | ||||
|     }); | ||||
| 
 | ||||
|     it('Resolve incident', () => { | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases/name/*?fields=*', | ||||
|         'getTestCase' | ||||
|       ); | ||||
|       interceptURL('GET', '/api/v1/feed?entityLink=*&type=Task', 'getTaskFeed'); | ||||
|       cy.sidebarClick(SidebarItem.INCIDENT_MANAGER); | ||||
|       cy.get(`[data-testid="test-case-${testCaseName}"]`).click(); | ||||
|       verifyResponseStatusCode('@getTestCase', 200); | ||||
|       cy.get('[data-testid="incident"]').click(); | ||||
|       verifyResponseStatusCode('@getTaskFeed', 200); | ||||
|       cy.get('[data-testid="task-cta-buttons"]') | ||||
|         .contains('Resolve') | ||||
|         .scrollIntoView() | ||||
|         .click(); | ||||
|       cy.get('#testCaseFailureReason').click(); | ||||
|       cy.get('[title="Missing Data"]').click(); | ||||
|       cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror') | ||||
|         .click() | ||||
|         .type('test'); | ||||
|       interceptURL( | ||||
|         'POST', | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus', | ||||
|         'updateTestCaseIncidentStatus' | ||||
|       ); | ||||
|       cy.get('.ant-modal-footer').contains('Submit').click(); | ||||
|       verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('Resolving incident & re-run pipeline', () => { | ||||
|     const testName = testCases[1]; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       cy.login(); | ||||
|     }); | ||||
| 
 | ||||
|     it("Acknowledge table test case's failure", () => { | ||||
|       acknowledgeTask(testName); | ||||
|     }); | ||||
| 
 | ||||
|     it('Resolve task from incident list page', () => { | ||||
|       goToProfilerTab(); | ||||
| 
 | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases?fields=*&entityLink=*&includeAllTests=true&limit=*', | ||||
|         'testCaseList' | ||||
|       ); | ||||
|       cy.get('[data-testid="profiler-tab-left-panel"]') | ||||
|         .contains('Data Quality') | ||||
|         .click(); | ||||
|       verifyResponseStatusCode('@testCaseList', 200); | ||||
|       cy.get(`[data-testid="${testName}"]`) | ||||
|         .find('.last-run-box.failed') | ||||
|         .scrollIntoView() | ||||
|         .should('be.visible'); | ||||
|       cy.get('.ant-table-row-level-0').should('contain', 'Ack'); | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus?latest=true&startTs=*&endTs=*&limit=*', | ||||
|         'getIncidentList' | ||||
|       ); | ||||
|       cy.sidebarClick(SidebarItem.INCIDENT_MANAGER); | ||||
| 
 | ||||
|       verifyResponseStatusCode('@getIncidentList', 200); | ||||
| 
 | ||||
|       cy.get(`[data-testid="test-case-${testName}"]`).should('be.visible'); | ||||
|       cy.get(`[data-testid="${testName}-status"]`) | ||||
|         .find(`[data-testid="edit-resolution-icon"]`) | ||||
|         .click(); | ||||
|       cy.get(`[data-testid="test-case-resolution-status-type"]`).click(); | ||||
|       cy.get(`[title="Resolved"]`).click(); | ||||
|       cy.get('#testCaseResolutionStatusDetails_testCaseFailureReason').click(); | ||||
|       cy.get('[title="Missing Data"]').click(); | ||||
|       cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror') | ||||
|         .click() | ||||
|         .type('test'); | ||||
|       interceptURL( | ||||
|         'POST', | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus', | ||||
|         'updateTestCaseIncidentStatus' | ||||
|       ); | ||||
|       cy.get('.ant-modal-footer').contains('Submit').click(); | ||||
|       verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200); | ||||
|     }); | ||||
| 
 | ||||
|     it('Task should be closed', () => { | ||||
|       goToProfilerTab(); | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases/name/*?fields=*', | ||||
|         'getTestCase' | ||||
|       ); | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases?fields=*&entityLink=*&includeAllTests=true&limit=*', | ||||
|         'testCaseList' | ||||
|       ); | ||||
|       interceptURL('GET', '/api/v1/feed?entityLink=*&type=Task', 'getTaskFeed'); | ||||
|       cy.get('[data-testid="profiler-tab-left-panel"]') | ||||
|         .contains('Data Quality') | ||||
|         .click(); | ||||
|       verifyResponseStatusCode('@testCaseList', 200); | ||||
|       cy.get(`[data-testid="${testName}"]`) | ||||
|         .find('.last-run-box.failed') | ||||
|         .scrollIntoView() | ||||
|         .should('be.visible'); | ||||
| 
 | ||||
|       cy.get(`[data-testid="${testName}"]`).contains(testName).click(); | ||||
|       verifyResponseStatusCode('@getTestCase', 200); | ||||
|       cy.get('[data-testid="incident"]').click(); | ||||
|       verifyResponseStatusCode('@getTaskFeed', 200); | ||||
|       cy.get('[data-testid="closed-task"]').click(); | ||||
|       cy.get('[data-testid="task-feed-card"]').should('be.visible'); | ||||
|       cy.get('[data-testid="task-tab"]').should( | ||||
|         'contain', | ||||
|         'Resolved the Task.' | ||||
|       ); | ||||
|     }); | ||||
| 
 | ||||
|     it('Re-run pipeline', () => { | ||||
|       triggerTestCasePipeline({ | ||||
|         serviceName: DATABASE_SERVICE.service.name, | ||||
|         tableName: TABLE_NAME, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('Verify open and closed task', () => { | ||||
|       acknowledgeTask(testName); | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases/name/*?fields=*', | ||||
|         'getTestCase' | ||||
|       ); | ||||
|       interceptURL('GET', '/api/v1/feed?entityLink=*&type=Task', 'getTaskFeed'); | ||||
|       cy.reload(); | ||||
|       verifyResponseStatusCode('@getTestCase', 200); | ||||
|       cy.get('[data-testid="incident"]').click(); | ||||
|       verifyResponseStatusCode('@getTaskFeed', 200); | ||||
|       cy.get('[data-testid="open-task"]') | ||||
|         .invoke('text') | ||||
|         .then((text) => { | ||||
|           expect(text.trim()).equal('1 Open'); | ||||
|         }); | ||||
|       cy.get('[data-testid="closed-task"]') | ||||
|         .invoke('text') | ||||
|         .then((text) => { | ||||
|           expect(text.trim()).equal('1 Closed'); | ||||
|         }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('Rerunning pipeline for an open incident', () => { | ||||
|     const testName = testCases[2]; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       cy.login(); | ||||
|     }); | ||||
| 
 | ||||
|     it('Ack incident and verify open task', () => { | ||||
|       acknowledgeTask(testName); | ||||
|       interceptURL( | ||||
|         'GET', | ||||
|         '/api/v1/dataQuality/testCases/name/*?fields=*', | ||||
|         'getTestCase' | ||||
|       ); | ||||
|       interceptURL('GET', '/api/v1/feed?entityLink=*&type=Task', 'getTaskFeed'); | ||||
|       cy.reload(); | ||||
|       verifyResponseStatusCode('@getTestCase', 200); | ||||
|       cy.get('[data-testid="incident"]').click(); | ||||
|       verifyResponseStatusCode('@getTaskFeed', 200); | ||||
|       cy.get('[data-testid="open-task"]') | ||||
|         .invoke('text') | ||||
|         .then((text) => { | ||||
|           expect(text.trim()).equal('1 Open'); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     it('Assign incident to user', () => { | ||||
|       assignIncident(testName); | ||||
|     }); | ||||
| 
 | ||||
|     it('Re-run pipeline', () => { | ||||
|       triggerTestCasePipeline({ | ||||
|         serviceName: DATABASE_SERVICE.service.name, | ||||
|         tableName: TABLE_NAME, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it("Verify incident's status on DQ page", () => { | ||||
|       goToProfilerTab(); | ||||
| 
 | ||||
|       cy.get('[data-testid="profiler-tab-left-panel"]') | ||||
|         .contains('Data Quality') | ||||
|         .click(); | ||||
|       cy.get(`[data-testid="${testName}"]`) | ||||
|         .find('.last-run-box.failed') | ||||
|         .scrollIntoView() | ||||
|         .should('be.visible'); | ||||
|       cy.get(`[data-testid="${testName}-status"]`).should( | ||||
|         'contain', | ||||
|         'Assigned' | ||||
|       ); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @ -0,0 +1,394 @@ | ||||
| /* | ||||
|  *  Copyright 2024 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 test, { expect } from '@playwright/test'; | ||||
| import { SidebarItem } from '../../constant/sidebar'; | ||||
| import { TableClass } from '../../support/entity/TableClass'; | ||||
| import { UserClass } from '../../support/user/UserClass'; | ||||
| import { | ||||
|   createNewPage, | ||||
|   descriptionBox, | ||||
|   getApiContext, | ||||
|   redirectToHomePage, | ||||
| } from '../../utils/common'; | ||||
| import { | ||||
|   acknowledgeTask, | ||||
|   assignIncident, | ||||
|   triggerTestSuitePipelineAndWaitForSuccess, | ||||
|   visitProfilerTab, | ||||
| } from '../../utils/incidentManager'; | ||||
| import { sidebarClick } from '../../utils/sidebar'; | ||||
| 
 | ||||
| const user1 = new UserClass(); | ||||
| const user2 = new UserClass(); | ||||
| const user3 = new UserClass(); | ||||
| const users = [user1, user2, user3]; | ||||
| const table1 = new TableClass(); | ||||
| 
 | ||||
| // use the admin user to login
 | ||||
| test.use({ storageState: 'playwright/.auth/admin.json' }); | ||||
| 
 | ||||
| test.describe.configure({ mode: 'serial' }); | ||||
| 
 | ||||
| test.describe('Incident Manager', () => { | ||||
|   test.beforeAll(async ({ browser }) => { | ||||
|     // since we need to poll for the pipeline status, we need to increase the timeout
 | ||||
|     test.setTimeout(90000); | ||||
| 
 | ||||
|     const { afterAction, apiContext, page } = await createNewPage(browser); | ||||
| 
 | ||||
|     const { pipeline } = await table1.createTestSuiteAndPipelines(apiContext); | ||||
|     for (let i = 0; i < 3; i++) { | ||||
|       await table1.createTestCase(apiContext, { | ||||
|         parameterValues: [ | ||||
|           { name: 'minColValue', value: 12 }, | ||||
|           { name: 'maxColValue', value: 24 }, | ||||
|         ], | ||||
|         testDefinition: 'tableColumnCountToBeBetween', | ||||
|       }); | ||||
|     } | ||||
|     await apiContext.post( | ||||
|       `/api/v1/services/ingestionPipelines/deploy/${pipeline.id}` | ||||
|     ); | ||||
|     await triggerTestSuitePipelineAndWaitForSuccess({ | ||||
|       page, | ||||
|       table: table1, | ||||
|       pipeline: { id: pipeline.id }, | ||||
|       apiContext, | ||||
|     }); | ||||
| 
 | ||||
|     for (const user of users) { | ||||
|       await user.create(apiContext); | ||||
|     } | ||||
| 
 | ||||
|     await afterAction(); | ||||
|   }); | ||||
| 
 | ||||
|   test.afterAll(async ({ browser }) => { | ||||
|     const { apiContext, afterAction } = await createNewPage(browser); | ||||
|     for (const entity of [...users, table1]) { | ||||
|       await entity.delete(apiContext); | ||||
|     } | ||||
|     await afterAction(); | ||||
|   }); | ||||
| 
 | ||||
|   test.slow(true); | ||||
| 
 | ||||
|   test.beforeEach(async ({ page }) => { | ||||
|     await redirectToHomePage(page); | ||||
|   }); | ||||
| 
 | ||||
|   test('Basic Scenario', async ({ page }) => { | ||||
|     const testCase = table1.testCasesResponseData[0]; | ||||
|     const testCaseName = testCase?.['name']; | ||||
|     const assignee = { | ||||
|       name: user1.data.email.split('@')[0], | ||||
|       displayName: user1.getUserName(), | ||||
|     }; | ||||
| 
 | ||||
|     await test.step("Acknowledge table test case's failure", async () => { | ||||
|       await acknowledgeTask({ | ||||
|         page, | ||||
|         testCase: testCaseName, | ||||
|         table: table1, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Assign incident to user', async () => { | ||||
|       await assignIncident({ | ||||
|         page, | ||||
|         testCaseName, | ||||
|         user: assignee, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Re-assign incident to user', async () => { | ||||
|       const assignee1 = { | ||||
|         name: user2.data.email.split('@')[0], | ||||
|         displayName: user2.getUserName(), | ||||
|       }; | ||||
|       const testCaseResponse = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases/name/*?fields=*' | ||||
|       ); | ||||
|       await page.click(`[data-testid="test-case-${testCaseName}"]`); | ||||
| 
 | ||||
|       await testCaseResponse; | ||||
| 
 | ||||
|       const incidentDetails = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus/stateId/*' | ||||
|       ); | ||||
|       await page.click('[data-testid="incident"]'); | ||||
|       await incidentDetails; | ||||
| 
 | ||||
|       await page.getByRole('button', { name: 'down' }).click(); | ||||
|       await page.waitForSelector('role=menuitem[name="Reassign"]', { | ||||
|         state: 'visible', | ||||
|       }); | ||||
|       await page.getByRole('menuitem', { name: 'Reassign' }).click(); | ||||
| 
 | ||||
|       const searchUserResponse = page.waitForResponse( | ||||
|         `/api/v1/search/suggest?q=*${user2.data.firstName}*${user2.data.lastName}*&index=user_search_index*` | ||||
|       ); | ||||
| 
 | ||||
|       await page.getByTestId('select-assignee').locator('div').click(); | ||||
|       await page.getByLabel('Assignee:').fill(assignee1.displayName); | ||||
|       await searchUserResponse; | ||||
| 
 | ||||
|       await page.click(`[data-testid="${assignee1.name.toLocaleLowerCase()}"]`); | ||||
|       const updateAssignee = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus' | ||||
|       ); | ||||
|       await page.getByRole('button', { name: 'Submit' }).click(); | ||||
| 
 | ||||
|       await updateAssignee; | ||||
|     }); | ||||
| 
 | ||||
|     await test.step( | ||||
|       "Re-assign incident from test case page's header", | ||||
|       async () => { | ||||
|         const assignee2 = { | ||||
|           name: user3.data.email.split('@')[0], | ||||
|           displayName: user3.getUserName(), | ||||
|         }; | ||||
|         const testCaseResponse = page.waitForResponse( | ||||
|           '/api/v1/dataQuality/testCases/name/*?fields=*' | ||||
|         ); | ||||
|         await page.reload(); | ||||
| 
 | ||||
|         await testCaseResponse; | ||||
| 
 | ||||
|         const listUserResponse = page.waitForResponse('/api/v1/users?*'); | ||||
|         await page.click('[data-testid="assignee"] [data-testid="edit-owner"]'); | ||||
|         listUserResponse; | ||||
|         await page.waitForSelector('[data-testid="loader"]', { | ||||
|           state: 'detached', | ||||
|         }); | ||||
| 
 | ||||
|         const searchUserResponse = page.waitForResponse( | ||||
|           '/api/v1/search/query?q=*' | ||||
|         ); | ||||
|         await page.fill( | ||||
|           '[data-testid="owner-select-users-search-bar"]', | ||||
|           assignee2.displayName | ||||
|         ); | ||||
|         await searchUserResponse; | ||||
| 
 | ||||
|         const updateIncident = page.waitForResponse( | ||||
|           '/api/v1/dataQuality/testCases/testCaseIncidentStatus' | ||||
|         ); | ||||
|         await page.click(`.ant-popover [title="${assignee2.displayName}"]`); | ||||
|         await updateIncident; | ||||
| 
 | ||||
|         await page.waitForSelector( | ||||
|           '[data-testid="assignee"] [data-testid="owner-link"]' | ||||
|         ); | ||||
| 
 | ||||
|         await expect( | ||||
|           page.locator('[data-testid="assignee"] [data-testid="owner-link"]') | ||||
|         ).toContainText(assignee2.displayName); | ||||
|       } | ||||
|     ); | ||||
| 
 | ||||
|     await test.step('Resolve incident', async () => { | ||||
|       await page.click('[data-testid="incident"]'); | ||||
|       await page.getByRole('button', { name: 'Resolve' }).click(); | ||||
|       await page.click('#testCaseFailureReason'); | ||||
|       await page.click('[title="Missing Data"]'); | ||||
|       await page.click(descriptionBox); | ||||
|       await page.fill(descriptionBox, 'test'); | ||||
| 
 | ||||
|       const updateIncident = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus' | ||||
|       ); | ||||
|       await page.click('.ant-modal-footer >> text=Submit'); | ||||
|       await updateIncident; | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   test('Resolving incident & re-run pipeline', async ({ page }) => { | ||||
|     const testCase = table1.testCasesResponseData[1]; | ||||
|     const testCaseName = testCase?.['name']; | ||||
|     const pipeline = table1.testSuitePipelineResponseData[0]; | ||||
|     const { apiContext } = await getApiContext(page); | ||||
| 
 | ||||
|     await test.step("Acknowledge table test case's failure", async () => { | ||||
|       await acknowledgeTask({ | ||||
|         page, | ||||
|         testCase: testCaseName, | ||||
|         table: table1, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Resolve task from incident list page', async () => { | ||||
|       await visitProfilerTab(page, table1); | ||||
|       const testCaseResponse = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases?fields=*' | ||||
|       ); | ||||
|       await page | ||||
|         .getByTestId('profiler-tab-left-panel') | ||||
|         .getByText('Data Quality') | ||||
|         .click(); | ||||
|       await testCaseResponse; | ||||
| 
 | ||||
|       await expect( | ||||
|         page.locator(`[data-testid="${testCaseName}"] .last-run-box.failed`) | ||||
|       ).toBeVisible(); | ||||
|       await expect(page.getByTestId(`${testCaseName}-status`)).toContainText( | ||||
|         'Ack' | ||||
|       ); | ||||
| 
 | ||||
|       const incidentDetailsRes = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus?latest=true&startTs=*&endTs=*&limit=*' | ||||
|       ); | ||||
|       await sidebarClick(page, SidebarItem.INCIDENT_MANAGER); | ||||
|       await incidentDetailsRes; | ||||
| 
 | ||||
|       await expect( | ||||
|         page.locator(`[data-testid="test-case-${testCaseName}"]`) | ||||
|       ).toBeVisible(); | ||||
| 
 | ||||
|       await page.click( | ||||
|         `[data-testid="${testCaseName}-status"] [data-testid="edit-resolution-icon"]` | ||||
|       ); | ||||
|       await page.click(`[data-testid="test-case-resolution-status-type"]`); | ||||
|       await page.click(`[title="Resolved"]`); | ||||
|       await page.click( | ||||
|         '#testCaseResolutionStatusDetails_testCaseFailureReason' | ||||
|       ); | ||||
|       await page.click('[title="Missing Data"]'); | ||||
|       await page.click(descriptionBox); | ||||
|       await page.fill(descriptionBox, 'test'); | ||||
|       const updateTestCaseIncidentStatus = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases/testCaseIncidentStatus' | ||||
|       ); | ||||
|       await page.click('.ant-modal-footer >> text=Submit'); | ||||
|       await updateTestCaseIncidentStatus; | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Task should be closed', async () => { | ||||
|       await visitProfilerTab(page, table1); | ||||
|       const testCaseResponse = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases?fields=*' | ||||
|       ); | ||||
|       await page | ||||
|         .getByTestId('profiler-tab-left-panel') | ||||
|         .getByText('Data Quality') | ||||
|         .click(); | ||||
|       await testCaseResponse; | ||||
| 
 | ||||
|       await expect( | ||||
|         page.locator(`[data-testid="${testCaseName}"] .last-run-box.failed`) | ||||
|       ).toBeVisible(); | ||||
| 
 | ||||
|       await page.click( | ||||
|         `[data-testid="${testCaseName}"] >> text=${testCaseName}` | ||||
|       ); | ||||
|       await page.click('[data-testid="incident"]'); | ||||
|       await page.click('[data-testid="closed-task"]'); | ||||
|       await page.waitForSelector('[data-testid="task-feed-card"]'); | ||||
| 
 | ||||
|       await expect(page.locator('[data-testid="task-tab"]')).toContainText( | ||||
|         'Resolved the Task.' | ||||
|       ); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Re-run pipeline', async () => { | ||||
|       await triggerTestSuitePipelineAndWaitForSuccess({ | ||||
|         page, | ||||
|         table: table1, | ||||
|         pipeline: { id: pipeline?.['id'] }, | ||||
|         apiContext, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Verify open and closed task', async () => { | ||||
|       await acknowledgeTask({ | ||||
|         page, | ||||
|         testCase: testCaseName, | ||||
|         table: table1, | ||||
|       }); | ||||
|       await page.reload(); | ||||
| 
 | ||||
|       await page.click('[data-testid="incident"]'); | ||||
| 
 | ||||
|       await expect(page.locator(`[data-testid="open-task"]`)).toHaveText( | ||||
|         '1 Open' | ||||
|       ); | ||||
|       await expect(page.locator(`[data-testid="closed-task"]`)).toHaveText( | ||||
|         '1 Closed' | ||||
|       ); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   test('Rerunning pipeline for an open incident', async ({ page }) => { | ||||
|     const testCase = table1.testCasesResponseData[2]; | ||||
|     const testCaseName = testCase?.['name']; | ||||
|     const pipeline = table1.testSuitePipelineResponseData[0]; | ||||
|     const assignee = { | ||||
|       name: user1.data.email.split('@')[0], | ||||
|       displayName: user1.getUserName(), | ||||
|     }; | ||||
|     const { apiContext } = await getApiContext(page); | ||||
| 
 | ||||
|     await test.step('Ack incident and verify open task', async () => { | ||||
|       await acknowledgeTask({ | ||||
|         page, | ||||
|         testCase: testCaseName, | ||||
|         table: table1, | ||||
|       }); | ||||
| 
 | ||||
|       await page.reload(); | ||||
| 
 | ||||
|       await page.click('[data-testid="incident"]'); | ||||
| 
 | ||||
|       await expect(page.locator(`[data-testid="open-task"]`)).toHaveText( | ||||
|         '1 Open' | ||||
|       ); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Assign incident to user', async () => { | ||||
|       await assignIncident({ | ||||
|         page, | ||||
|         testCaseName, | ||||
|         user: assignee, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step('Re-run pipeline', async () => { | ||||
|       await triggerTestSuitePipelineAndWaitForSuccess({ | ||||
|         page, | ||||
|         table: table1, | ||||
|         pipeline: { id: pipeline?.['id'] }, | ||||
|         apiContext, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     await test.step("Verify incident's status on DQ page", async () => { | ||||
|       await visitProfilerTab(page, table1); | ||||
|       const testCaseResponse = page.waitForResponse( | ||||
|         '/api/v1/dataQuality/testCases?fields=*' | ||||
|       ); | ||||
|       await page | ||||
|         .getByTestId('profiler-tab-left-panel') | ||||
|         .getByText('Data Quality') | ||||
|         .click(); | ||||
|       await testCaseResponse; | ||||
| 
 | ||||
|       await expect( | ||||
|         page.locator(`[data-testid="${testCaseName}"] .last-run-box.failed`) | ||||
|       ).toBeVisible(); | ||||
|       await expect(page.getByTestId(`${testCaseName}-status`)).toContainText( | ||||
|         'Assigned' | ||||
|       ); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @ -65,3 +65,8 @@ export enum ENTITY_PATH { | ||||
|   'apiEndpoints' = 'apiEndpoint', | ||||
|   'dataProducts' = 'dataProduct', | ||||
| } | ||||
| 
 | ||||
| export type TestCaseData = { | ||||
|   parameterValues: unknown[]; | ||||
|   testDefinition: string; | ||||
| }; | ||||
|  | ||||
| @ -14,7 +14,7 @@ import { APIRequestContext, Page } from '@playwright/test'; | ||||
| import { SERVICE_TYPE } from '../../constant/service'; | ||||
| import { uuid } from '../../utils/common'; | ||||
| import { visitEntityPage } from '../../utils/entity'; | ||||
| import { EntityTypeEndpoint } from './Entity.interface'; | ||||
| import { EntityTypeEndpoint, TestCaseData } from './Entity.interface'; | ||||
| import { EntityClass } from './EntityClass'; | ||||
| 
 | ||||
| export class TableClass extends EntityClass { | ||||
| @ -169,7 +169,7 @@ export class TableClass extends EntityClass { | ||||
| 
 | ||||
|   async createTestSuiteAndPipelines(apiContext: APIRequestContext) { | ||||
|     if (!this.entityResponseData) { | ||||
|       return this.create(apiContext); | ||||
|       await this.create(apiContext); | ||||
|     } | ||||
| 
 | ||||
|     const testSuiteData = await apiContext | ||||
| @ -177,7 +177,7 @@ export class TableClass extends EntityClass { | ||||
|         data: { | ||||
|           name: `pw-test-suite-${uuid()}`, | ||||
|           executableEntityReference: | ||||
|             this.entityResponseData['fullyQualifiedName'], | ||||
|             this.entityResponseData?.['fullyQualifiedName'], | ||||
|           description: 'Playwright test suite for table', | ||||
|         }, | ||||
|       }) | ||||
| @ -221,12 +221,16 @@ export class TableClass extends EntityClass { | ||||
|         }, | ||||
|       }) | ||||
|       .then((res) => res.json()); | ||||
| 
 | ||||
|     this.testSuitePipelineResponseData.push(pipelineData); | ||||
| 
 | ||||
|     return pipelineData; | ||||
|   } | ||||
| 
 | ||||
|   async createTestCase(apiContext: APIRequestContext) { | ||||
|   async createTestCase( | ||||
|     apiContext: APIRequestContext, | ||||
|     testCaseData?: TestCaseData | ||||
|   ) { | ||||
|     if (!this.testSuiteResponseData) { | ||||
|       await this.createTestSuiteAndPipelines(apiContext); | ||||
|     } | ||||
| @ -236,9 +240,10 @@ export class TableClass extends EntityClass { | ||||
|         data: { | ||||
|           name: `pw-test-case-${uuid()}`, | ||||
|           entityLink: `<#E::table::${this.entityResponseData?.['fullyQualifiedName']}>`, | ||||
|           testDefinition: 'tableRowCountToBeBetween', | ||||
|           testDefinition: | ||||
|             testCaseData?.testDefinition ?? 'tableRowCountToBeBetween', | ||||
|           testSuite: this.testSuiteResponseData?.['fullyQualifiedName'], | ||||
|           parameterValues: [ | ||||
|           parameterValues: testCaseData?.parameterValues ?? [ | ||||
|             { name: 'minValue', value: 12 }, | ||||
|             { name: 'maxValue', value: 34 }, | ||||
|           ], | ||||
|  | ||||
| @ -0,0 +1,128 @@ | ||||
| /* | ||||
|  *  Copyright 2024 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 { APIRequestContext, expect, Page } from '@playwright/test'; | ||||
| import { SidebarItem } from '../constant/sidebar'; | ||||
| import { TableClass } from '../support/entity/TableClass'; | ||||
| import { redirectToHomePage } from './common'; | ||||
| import { sidebarClick } from './sidebar'; | ||||
| 
 | ||||
| export const visitProfilerTab = async (page: Page, table: TableClass) => { | ||||
|   await redirectToHomePage(page); | ||||
|   await table.visitEntityPage(page); | ||||
|   await page.click('[data-testid="profiler"]'); | ||||
| }; | ||||
| 
 | ||||
| export const acknowledgeTask = async (data: { | ||||
|   testCase: string; | ||||
|   page: Page; | ||||
|   table: TableClass; | ||||
| }) => { | ||||
|   const { testCase, page, table } = data; | ||||
|   await visitProfilerTab(page, table); | ||||
|   await page.click('[data-testid="profiler-tab-left-panel"]'); | ||||
|   await page | ||||
|     .getByTestId('profiler-tab-left-panel') | ||||
|     .getByText('Data Quality') | ||||
|     .click(); | ||||
|   await page.click(`[data-testid="${testCase}"] >> .last-run-box.failed`); | ||||
|   await page.waitForSelector(`[data-testid="${testCase}-status"] >> text=New`); | ||||
|   await page.click(`[data-testid="${testCase}"] >> text=${testCase}`); | ||||
|   await page.click('[data-testid="edit-resolution-icon"]'); | ||||
|   await page.click('[data-testid="test-case-resolution-status-type"]'); | ||||
|   await page.click('[title="Ack"]'); | ||||
|   const statusChangeResponse = page.waitForResponse( | ||||
|     '/api/v1/dataQuality/testCases/testCaseIncidentStatus' | ||||
|   ); | ||||
|   await page.click('#update-status-button'); | ||||
|   await statusChangeResponse; | ||||
|   await page.waitForSelector(`[data-testid="${testCase}-status"] >> text=Ack`); | ||||
| }; | ||||
| 
 | ||||
| export const assignIncident = async (data: { | ||||
|   testCaseName: string; | ||||
|   page: Page; | ||||
|   user: { name: string; displayName: string }; | ||||
| }) => { | ||||
|   const { testCaseName, page, user } = data; | ||||
|   await sidebarClick(page, SidebarItem.INCIDENT_MANAGER); | ||||
|   await page.waitForSelector(`[data-testid="test-case-${testCaseName}"]`); | ||||
|   await page.click( | ||||
|     `[data-testid="${testCaseName}-status"] [data-testid="edit-resolution-icon"]` | ||||
|   ); | ||||
|   await page.click('[data-testid="test-case-resolution-status-type"]'); | ||||
|   await page.click('[title="Assigned"]'); | ||||
|   await page.waitForSelector('#testCaseResolutionStatusDetails_assignee'); | ||||
|   await page.fill( | ||||
|     '#testCaseResolutionStatusDetails_assignee', | ||||
|     user.displayName | ||||
|   ); | ||||
|   await page.waitForResponse('/api/v1/search/suggest?q=*'); | ||||
|   await page.click(`[data-testid="${user.name.toLocaleLowerCase()}"]`); | ||||
|   const updateIncident = page.waitForResponse( | ||||
|     '/api/v1/dataQuality/testCases/testCaseIncidentStatus' | ||||
|   ); | ||||
|   await page.click('#update-status-button'); | ||||
|   await updateIncident; | ||||
|   await page.waitForSelector( | ||||
|     `[data-testid="${testCaseName}-status"] [data-testid="badge-container"] >> text=Assigned` | ||||
|   ); | ||||
| 
 | ||||
|   await expect( | ||||
|     page.locator( | ||||
|       `[data-testid="${testCaseName}-status"] [data-testid="badge-container"]` | ||||
|     ) | ||||
|   ).toContainText('Assigned'); | ||||
| }; | ||||
| 
 | ||||
| export const triggerTestSuitePipelineAndWaitForSuccess = async (data: { | ||||
|   page: Page; | ||||
|   apiContext: APIRequestContext; | ||||
|   table: TableClass; | ||||
|   pipeline: { id: string }; | ||||
| }) => { | ||||
|   const { page, apiContext, table, pipeline } = data; | ||||
|   // wait for 2s before the pipeline to be run
 | ||||
|   await page.waitForTimeout(2000); | ||||
|   await apiContext | ||||
|     .post(`/api/v1/services/ingestionPipelines/trigger/${pipeline.id}`) | ||||
|     .then((res) => { | ||||
|       if (res.status() !== 200) { | ||||
|         return apiContext.post( | ||||
|           `/api/v1/services/ingestionPipelines/trigger/${pipeline.id}` | ||||
|         ); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|   // Wait for the run to complete
 | ||||
|   await page.waitForTimeout(2000); | ||||
| 
 | ||||
|   await expect | ||||
|     .poll( | ||||
|       async () => { | ||||
|         const response = await apiContext | ||||
|           .get( | ||||
|             `/api/v1/services/ingestionPipelines?fields=pipelineStatuses&testSuite=${table.testSuiteResponseData?.['fullyQualifiedName']}&pipelineType=TestSuite` | ||||
|           ) | ||||
|           .then((res) => res.json()); | ||||
| 
 | ||||
|         return response.data?.[0]?.pipelineStatuses?.pipelineState; | ||||
|       }, | ||||
|       { | ||||
|         // Custom expect message for reporting, optional.
 | ||||
|         message: 'Wait for the pipeline to be successful', | ||||
|         timeout: 60_000, | ||||
|         intervals: [5_000, 10_000], | ||||
|       } | ||||
|     ) | ||||
|     .toBe('success'); | ||||
| }; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Shailesh Parmar
						Shailesh Parmar