Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

additional cypress test case for pipeline detail #2746

Merged
merged 1 commit into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading