Skip to content

Commit

Permalink
additional cypress test case for pipeline detail
Browse files Browse the repository at this point in the history
  • Loading branch information
pnaik1 committed Apr 26, 2024
1 parent 5a3a6b2 commit e5415d2
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import { mockDataSciencePipelineApplicationK8sResource } from '~/__mocks__/mockDataSciencePipelinesApplicationK8sResource';
import { mockDscStatus } from '~/__mocks__/mockDscStatus';
import { mockK8sResourceList } from '~/__mocks__/mockK8sResourceList';
import { buildMockPipelineVersionV2 } from '~/__mocks__/mockPipelineVersionsProxy';
import {
buildMockPipelineVersionV2,
buildMockPipelineVersionsV2,
} from '~/__mocks__/mockPipelineVersionsProxy';
import { mockProjectK8sResource } from '~/__mocks__/mockProjectK8sResource';
import { mockRouteK8sResource } from '~/__mocks__/mockRouteK8sResource';
import { mockSecretK8sResource } from '~/__mocks__/mockSecretK8sResource';
Expand All @@ -12,6 +15,7 @@ import {
pipelineDetails,
pipelineRunJobDetails,
pipelineRunDetails,
pipelineVersionImportModal,
} from '~/__tests__/cypress/cypress/pages/pipelines';
import { buildMockRunKF } from '~/__mocks__/mockRunKF';
import { mockPipelinePodK8sResource } from '~/__mocks__/mockPipelinePodK8sResource';
Expand All @@ -24,6 +28,8 @@ import {
RouteModel,
SecretModel,
} from '~/__tests__/cypress/cypress/utils/models';
import { mock200Status } from '~/__mocks__/mockK8sStatus';
import { deleteModal } from '~/__tests__/cypress/cypress/pages/components/DeleteModal';

const projectId = 'test-project';
const mockPipeline = buildMockPipelineV2({
Expand All @@ -35,6 +41,11 @@ const mockVersion = buildMockPipelineVersionV2({
pipeline_version_id: 'test-version-id',
display_name: 'test-version-name',
});
const mockVersion2 = buildMockPipelineVersionV2({
pipeline_id: mockPipeline.pipeline_id,
pipeline_version_id: 'test-version-id-2',
display_name: 'test-version-2',
});
const mockRun = buildMockRunKF({
display_name: 'test-pipeline-run',
run_id: 'test-pipeline-run-id',
Expand Down Expand Up @@ -109,6 +120,13 @@ const initIntercepts = () => {
},
mockPipeline,
);
cy.intercept(
{
method: 'GET',
pathname: `/api/service/pipelines/${projectId}/dspa/apis/v2beta1/pipelines/${mockPipeline.pipeline_id}/versions`,
},
buildMockPipelineVersionsV2([mockVersion, mockVersion2]),
);

cy.intercept(
{
Expand Down Expand Up @@ -181,16 +199,15 @@ const initIntercepts = () => {

describe('Pipeline topology', () => {
describe('Pipeline details', () => {
beforeEach(() => {
initIntercepts();
pipelineDetails.visit(projectId, mockVersion.pipeline_id, mockVersion.pipeline_version_id);
// https://issues.redhat.com/browse/RHOAIENG-4562
// Bypass intermittent Cypress error:
// Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https://cdn.jsdelivr.net/npm/[email protected]/min/vs/base/worker/workerMain.js' failed to load.
Cypress.on('uncaught:exception', () => false);
});
describe('Navigation', () => {
beforeEach(() => {
initIntercepts();
pipelineDetails.visit(projectId, mockVersion.pipeline_id, mockVersion.pipeline_version_id);
// https://issues.redhat.com/browse/RHOAIENG-4562
// Bypass intermittent Cypress error:
// Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https://cdn.jsdelivr.net/npm/[email protected]/min/vs/base/worker/workerMain.js' failed to load.
Cypress.on('uncaught:exception', () => false);
});

it('Test pipeline details create run navigation', () => {
pipelineDetails.selectActionDropdownItem('Create run');
verifyRelativeURL(`/pipelineRuns/${projectId}/pipelineRun/create`);
Expand All @@ -211,6 +228,91 @@ describe('Pipeline topology', () => {
verifyRelativeURL(`/pipelineRuns/${projectId}?runType=scheduled`);
});
});

it('validate clicking on node will open a drawer from right with data.', () => {
pipelineDetails.findTaskNode('create-dataset').click();
const taskDrawer = pipelineDetails.getTaskDrawer();
taskDrawer.shouldHaveTaskName('create-dataset ');
taskDrawer.findInputArtifacts().should('not.exist');
taskDrawer.findOutputParameters().should('not.exist');
taskDrawer.findOutputArtifacts().should('exist');
taskDrawer.findCommandCodeBlock().should('not.be.empty');
taskDrawer.findArgumentCodeBlock().should('not.be.empty');
taskDrawer.findTaskImage().should('have.text', 'Imagequay.io/hukhan/iris-base:1');
taskDrawer.findCloseDrawerButton().click();
taskDrawer.find().should('not.exist');
});

it('delete pipeline version from action dropdown', () => {
pipelineDetails.selectActionDropdownItem('Delete pipeline version');
deleteModal.shouldBeOpen();
deleteModal.findInput().type(mockVersion.display_name);
cy.intercept(
{
method: 'DELETE',
pathname: `/api/service/pipelines/${projectId}/dspa/apis/v2beta1/pipelines/${mockPipeline.pipeline_id}/versions/${mockVersion.pipeline_version_id}`,
},
mock200Status({}),
).as('deletePipelineVersion');

deleteModal.findSubmitButton().click();
cy.wait('@deletePipelineVersion');
});

it('page details are updated when a new pipeline version is selected', () => {
cy.intercept(
{
method: 'GET',
pathname: `/api/service/pipelines/${projectId}/dspa/apis/v2beta1/pipelines/${mockPipeline.pipeline_id}/versions/${mockVersion2.pipeline_version_id}`,
},
mockVersion2,
);
pipelineDetails.selectPipelineVersionByName(mockVersion2.display_name);
pipelineDetails.findPageTitle().should('have.text', 'test-version-2');
verifyRelativeURL(
`/pipelines/${projectId}/pipeline/view/${mockPipeline.pipeline_id}/${mockVersion2.pipeline_version_id}`,
);
});

it('page details are updated after uploading a new version', () => {
cy.intercept(
{
method: 'GET',
pathname: `/api/service/pipelines/${projectId}/dspa/apis/v2beta1/pipelines/${mockPipeline.pipeline_id}/versions/${mockVersion2.pipeline_version_id}`,
},
mockVersion2,
);
pipelineDetails.findPageTitle().should('have.text', 'test-version-name');
pipelineDetails.selectActionDropdownItem('Upload new version');
pipelineVersionImportModal.findImportPipelineRadio().check();
pipelineVersionImportModal.findPipelineUrlInput().type('https://example.com/pipeline.yaml');
cy.intercept(
{
method: 'POST',
pathname: `/api/service/pipelines/${projectId}/dspa/apis/v2beta1/pipelines/${mockPipeline.pipeline_id}/versions`,
},
mockVersion2,
).as('uploadNewPipelineVersion');

pipelineVersionImportModal.submit();
verifyRelativeURL(
`/pipelines/${projectId}/pipeline/view/${mockPipeline.pipeline_id}/${mockVersion2.pipeline_version_id}`,
);
cy.wait('@uploadNewPipelineVersion').then((interception) => {
expect(interception.request.body).to.containSubset({
pipeline_id: 'test-pipeline',
description: '',
package_url: { pipeline_url: 'https://example.com/pipeline.yaml' },
});
});
pipelineDetails.findPageTitle().should('have.text', 'test-version-2');
});

it('validate for Yaml tab in pipeline details tab', () => {
pipelineDetails.findYamlTab().click();
const pipelineDashboardCodeEditor = pipelineDetails.getPipelineDashboardCodeEditor();
pipelineDashboardCodeEditor.findInput().should('not.be.empty');
});
});

describe('Pipeline run details', () => {
Expand Down
75 changes: 66 additions & 9 deletions frontend/src/__tests__/cypress/cypress/pages/pipelines/topology.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,39 @@
import { Contextual } from '~/__tests__/cypress/cypress/pages/components/Contextual';
import { DashboardCodeEditor } from '~/__tests__/cypress/cypress/pages/components/DashboardCodeEditor';

class TaskDrawer extends Contextual<HTMLElement> {
findInputArtifacts() {
return this.find().findByTestId('Input-artifacts');
}

findCommandCodeBlock() {
return this.find().findByTestId('command-task-detail-code-block').findByRole('code');
}

findTaskImage() {
return this.find().findByTestId('task-detail-image');
}

findArgumentCodeBlock() {
return this.find().findByTestId('arguments-task-detail-code-block').findByRole('code');
}

findOutputArtifacts() {
return this.find().findByTestId('Output-artifacts');
}

findOutputParameters() {
return this.find().findByTestId('Output-parameters');
}

findCloseDrawerButton() {
return this.find().findByRole('button', { name: 'Close drawer panel' });
}

shouldHaveTaskName(name: string) {
return this.find().findByTestId('pipeline-task-name').should('have.text', name);
}
}

class PipelinesTopology {
visit(namespace: string, pipelineId: string, pipelineVersionId: string) {
Expand All @@ -13,14 +48,6 @@ class PipelinesTopology {
findTaskNode(name: string) {
return cy.get(`[data-id="${name}"][data-kind="node"][data-type="DEFAULT_TASK_NODE"]`);
}

findTaskDrawer() {
return cy.findByTestId('task-drawer');
}

findCloseDrawerButton() {
return this.findTaskDrawer().findByRole('button', { name: 'Close drawer panel' });
}
}

class PipelineRunRightDrawer extends Contextual<HTMLDivElement> {
Expand Down Expand Up @@ -75,7 +102,37 @@ class PipelineDetails extends PipelinesTopology {
this.wait();
}

findActionsDropdown() {
private findPipelineVersionSelect() {
return cy.findByTestId('pipeline-version-toggle-button');
}

selectPipelineVersionByName(name: string): void {
this.findPipelineVersionSelect()
.click()
.parents()
.findByTestId('pipeline-version-selector-table-list')
.find('td')
.contains(name)
.click();
}

findYamlTab() {
return cy.findByTestId('pipeline-yaml-tab');
}

getPipelineDashboardCodeEditor() {
return new DashboardCodeEditor(() => cy.findByTestId('pipeline-dashboard-code-editor'));
}

findPageTitle() {
return cy.findByTestId('app-page-title');
}

getTaskDrawer() {
return new TaskDrawer(() => cy.findByTestId('task-drawer'));
}

private findActionsDropdown() {
return cy.findByTestId('pipeline-version-details-actions');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const PipelineDetailsYAML: React.FC<PipelineDetailsYAMLProps> = ({ filename, con

return (
<DashboardCodeEditor
testId="pipeline-dashboard-code-editor"
code={pipelineYAML}
downloadFileName={filename ?? 'Pipeline content'}
isDownloadEnabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ const PipelineDetails: PipelineCoreDetailsPageComponent = ({ breadcrumbPath }) =
<Tab
eventKey={PipelineDetailsTab.YAML}
title={<TabTitleText>YAML</TabTitleText>}
data-testid="pipeline-yaml-tab"
aria-label="Pipeline YAML Tab"
tabContentId={`tabContent-${PipelineDetailsTab.YAML}`}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,29 @@ const PipelineTaskDetails: React.FC<TaskDetailsProps> = ({ task }) => {
{task.steps?.map((step, i) => (
<React.Fragment key={i}>
<StackItem>
<TaskDetailsSection title="Image">{step.image}</TaskDetailsSection>
<TaskDetailsSection testId="task-detail-image" title="Image">
{step.image}
</TaskDetailsSection>
</StackItem>
{step.command && (
<StackItem>
<TaskDetailsSection title="Command">
<TaskDetailsCodeBlock id="command" content={step.command.join('\n')} />
<TaskDetailsCodeBlock
id="command"
testId="command-task-detail-code-block"
content={step.command.join('\n')}
/>
</TaskDetailsSection>
</StackItem>
)}
{step.args && (
<StackItem>
<TaskDetailsSection title="Arguments">
<TaskDetailsCodeBlock id="args" content={step.args.join('\n')} />
<TaskDetailsCodeBlock
id="args"
testId="arguments-task-detail-code-block"
content={step.args.join('\n')}
/>
</TaskDetailsSection>
</StackItem>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const SelectedTaskDrawerContent: React.FC<SelectedTaskDrawerContentProps> = ({ t
data-testid="task-drawer"
>
<DrawerHead>
<Title headingLevel="h2" size="xl">
<Title headingLevel="h2" size="xl" data-testid="pipeline-task-name">
{task.name} {task.type === 'artifact' ? 'Artifact details' : ''}
</Title>
<DrawerActions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {
type TaskDetailsCodeBlockProps = {
id: string;
content: string;
testId?: string;
};

const TaskDetailsCodeBlock: React.FC<TaskDetailsCodeBlockProps> = ({ id, content }) => {
const TaskDetailsCodeBlock: React.FC<TaskDetailsCodeBlockProps> = ({ id, content, testId }) => {
const [copied, setCopied] = React.useState(false);

const clipboardCopyFunc = (text: string) => {
Expand All @@ -25,6 +26,7 @@ const TaskDetailsCodeBlock: React.FC<TaskDetailsCodeBlockProps> = ({ id, content

return (
<CodeBlock
data-testid={testId}
actions={
<CodeBlockAction>
<ClipboardCopyButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ const TaskDetailsInputOutput: React.FC<TaskDetailsInputOutputProps> = ({
<Stack hasGutter>
{artifacts && (
<StackItem>
<TaskDetailsSection title={`${type} artifacts`}>
<TaskDetailsSection title={`${type} artifacts`} testId={`${type}-artifacts`}>
<TaskDetailsPrintKeyValues items={artifacts} />
</TaskDetailsSection>
</StackItem>
)}
{params && (
<StackItem>
<TaskDetailsSection title={`${type} parameters`}>
<TaskDetailsSection title={`${type} parameters`} testId={`${type}-parameters`}>
<TaskDetailsPrintKeyValues items={params} />
</TaskDetailsSection>
</StackItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { Stack, StackItem, Title } from '@patternfly/react-core';
type TaskDetailsSectionProps = {
title: string;
children: React.ReactNode;
testId?: string;
};

const TaskDetailsSection: React.FC<TaskDetailsSectionProps> = ({ title, children }) => (
<Stack hasGutter>
const TaskDetailsSection: React.FC<TaskDetailsSectionProps> = ({ title, children, testId }) => (
<Stack hasGutter data-testid={testId}>
<StackItem>
<Title headingLevel="h3" size="lg">
{title}
Expand Down

0 comments on commit e5415d2

Please sign in to comment.