Skip to content

Commit

Permalink
Refactor the project dropdown (#3172)
Browse files Browse the repository at this point in the history
* Refactor the project dropdown

* Improve cross usage of types in bad DRY code

* Address cypress test situation around shared component

* Embrace a pure css solution to the truncate no-min-width

* Added back the isDisabled flag to the pipeline selector variants
  • Loading branch information
andrewballantyne authored Sep 12, 2024
1 parent 80be394 commit 4a6ab8a
Show file tree
Hide file tree
Showing 25 changed files with 574 additions and 516 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { SubComponentBase } from '~/__tests__/cypress/cypress/pages/components/subComponents/SubComponentBase';

export class SearchSelector extends SubComponentBase {
constructor(private selectorId: string, contextSelectorId?: string) {
super(contextSelectorId);
}

private findContextualItem(suffix: string): Cypress.Chainable<JQuery<HTMLElement>> {
return this.findScope().findByTestId(`${this.selectorId}-${suffix}`);
}

findItem(name: string): Cypress.Chainable<JQuery<HTMLElement>> {
return this.findToggleButton().findDropdownItem(name);
}

selectItem(name: string): void {
this.findItem(name).click();
}

findSearchInput(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.findContextualItem('search');
}

findToggleButton(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.findContextualItem('toggle');
}

findSearchHelpText(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.findContextualItem('searchHelpText');
}

findMenu(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.findContextualItem('menu');
}

findMenuList(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.findContextualItem('menuList');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* A SubComponent is a component that doesn't make up a full page and will be consumed in other page
* objects. This could be a complex field, a group of fields, or some section. Typically not large
* enough to warrant its own standalone page object.
*
* Primary use-case example:
* class Foo extends SubComponentBase {
* constructor(private myTestId: string, scopedTestId?: string) {
* super(scopedTestId);
* }
*
* private find(suffix: string) {
* return this.findScope().getByTestId(`${this.myTestId}-${suffix}`);
* }
*
* selectItem(name: string) {
* // "list" would be an internal suffix for your component to know where the "items" are
* return this.find('list').findDropdownItem(name);
* }
* }
*
* Search uses of this component to see further examples
*/
export class SubComponentBase {
constructor(private scopedBaseTestId?: string) {}

/** Allows for extended classes to make use of a simple one-check for their `find()` calls */
protected findScope(): (Cypress.cy & CyEventEmitter) | Cypress.Chainable<JQuery<HTMLElement>> {
if (this.scopedBaseTestId) {
return cy.findByTestId(this.scopedBaseTestId);
}

return cy;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { appChrome } from '~/__tests__/cypress/cypress/pages/appChrome';
import type { RefreshIntervalTitle } from '~/concepts/metrics/types';
import { SearchSelector } from '~/__tests__/cypress/cypress/pages/components/subComponents/SearchSelector';

class GlobalDistributedWorkloads {
projectDropdown = new SearchSelector('project-selector');

visit(wait = true) {
cy.visitWithLogin(`/distributedWorkloads`);
if (wait) {
Expand All @@ -26,10 +29,6 @@ class GlobalDistributedWorkloads {
return cy.findByTestId('app-page-title').should('have.text', 'Distributed Workload Metrics');
}

findProjectSelect() {
return cy.findByTestId('project-selector-dropdown');
}

findRefreshIntervalSelectToggle() {
return cy.get('#metrics-toolbar-refresh-interval-select-toggle');
}
Expand All @@ -42,10 +41,6 @@ class GlobalDistributedWorkloads {
this.findRefreshIntervalSelectToggle().should('contain.text', interval);
}

selectProjectByName(name: string) {
this.findProjectSelect().findDropdownItem(name).click();
}

findStatusOverviewCard() {
return cy.findByTestId('dw-status-overview-card');
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SearchSelector } from '~/__tests__/cypress/cypress/pages/components/subComponents/SearchSelector';

export enum FormFieldSelector {
MODEL_NAME = '#model-name',
MODEL_DESCRIPTION = '#model-description',
Expand All @@ -15,6 +17,8 @@ export enum FormFieldSelector {
}

class RegisterModelPage {
projectDropdown = new SearchSelector('project-selector', 'connection-autofill-modal');

visit() {
const preferredModelRegistry = 'modelregistry-sample';
cy.visitWithLogin(`/modelRegistry/${preferredModelRegistry}/registerModel`);
Expand All @@ -41,10 +45,6 @@ class RegisterModelPage {
return cy.findByTestId('connection-autofill-modal');
}

findProjectSelector() {
return this.findConnectionAutofillModal().findByTestId('project-selector-dropdown');
}

findConnectionSelector() {
return this.findConnectionAutofillModal().findByTestId('select-data-connection');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { buildMockPipelines } from '~/__mocks__/mockPipelinesProxy';
import { buildMockPipelineVersionsV2 } from '~/__mocks__/mockPipelineVersionsProxy';
import { Contextual } from '~/__tests__/cypress/cypress/pages/components/Contextual';
import { buildMockRecurringRunKF } from '~/__mocks__/mockRecurringRunKF';
import { SearchSelector } from '~/__tests__/cypress/cypress/pages/components/subComponents/SearchSelector';

class ParamsSection extends Contextual<HTMLElement> {
findParamById(id: string): Cypress.Chainable<JQuery<HTMLElement>> {
Expand All @@ -28,6 +29,12 @@ export class CreateRunPage {

private type;

experimentSelect = new SearchSelector('experiment-selector');

pipelineSelect = new SearchSelector('pipeline-selector');

pipelineVersionSelect = new SearchSelector('pipeline-version-selector');

constructor(type: 'run' | 'schedule') {
this.type = type;
}
Expand All @@ -48,18 +55,6 @@ export class CreateRunPage {
return this.find().findByTestId('run-type-section-alert-link');
}

findExperimentSelect(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.find().findByTestId('experiment-toggle-button');
}

findPipelineSelect(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.find().findByTestId('pipeline-toggle-button');
}

findPipelineVersionSelect(): Cypress.Chainable<JQuery<HTMLElement>> {
return this.find().findByTestId('pipeline-version-toggle-button');
}

findPipelineVersionByName(name: string): Cypress.Chainable<JQuery<HTMLTableCellElement>> {
return this.find()
.findByTestId('pipeline-version-selector-table-list')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import type {
} from '~/concepts/pipelines/kfTypes';
import { buildMockPipelineVersionV2 } from '~/__mocks__/mockPipelineVersionsProxy';
import { Modal } from '~/__tests__/cypress/cypress/pages/components/Modal';
import { SearchSelector } from '~/__tests__/cypress/cypress/pages/components/subComponents/SearchSelector';

class PipelineImportModal extends Modal {
pipelineSelector = new SearchSelector('pipeline-selector');

constructor() {
super('Upload new version');
}
Expand All @@ -18,10 +21,6 @@ class PipelineImportModal extends Modal {
return this.findFooter().findByRole('button', { name: 'Upload', hidden: true });
}

findPipelineSelect() {
return this.find().findByTestId('pipeline-toggle-button');
}

findVersionNameInput() {
return this.find().findByTestId('pipeline-version-name');
}
Expand Down Expand Up @@ -59,7 +58,8 @@ class PipelineImportModal extends Modal {
}

selectPipelineByName(name: string) {
this.findPipelineSelect()
this.pipelineSelector
.findToggleButton()
.click()
.parents()
.findByTestId('pipeline-selector-table-list')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { DeleteModal } from '~/__tests__/cypress/cypress/pages/components/DeleteModal';
import { Modal } from '~/__tests__/cypress/cypress/pages/components/Modal';
import { appChrome } from '~/__tests__/cypress/cypress/pages/appChrome';
import { SearchSelector } from '~/__tests__/cypress/cypress/pages/components/subComponents/SearchSelector';

class PipelinesGlobal {
projectDropdown = new SearchSelector('project-selector');

visit(projectName: string) {
cy.visitWithLogin(`/pipelines/${projectName}`);
this.wait();
Expand Down Expand Up @@ -48,10 +51,6 @@ class PipelinesGlobal {
return cy.findByRole('menuitem').get('span').contains('Upload new version');
}

findProjectSelect() {
return cy.findByTestId('project-selector-dropdown');
}

isApiAvailable() {
return cy.findByTestId('pipelines-api-not-available').should('not.exist');
}
Expand All @@ -64,10 +63,6 @@ class PipelinesGlobal {
return this.findIsServerIncompatible().findByTestId('delete-pipeline-server-button');
}

selectProjectByName(name: string) {
this.findProjectSelect().findDropdownItem(name).click();
}

findDeleteButton() {
return cy.findByTestId('global-pipelines-kebab-actions').findDropdownItem('Delete');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
PipelineRecurringRunKFv2,
PipelineVersionKFv2,
} from '~/concepts/pipelines/kfTypes';
import { SearchSelector } from '~/__tests__/cypress/cypress/pages/components/subComponents/SearchSelector';

class TaskDrawer extends Contextual<HTMLElement> {
findInputArtifacts() {
Expand Down Expand Up @@ -150,17 +151,16 @@ class DetailsItem extends Contextual<HTMLElement> {
}

class PipelineDetails extends PipelinesTopology {
pipelineVersionSelector = new SearchSelector('pipeline-version-selector');

visit(namespace: string, pipelineId: string, pipelineVersionId: string) {
cy.visitWithLogin(`/pipelines/${namespace}/${pipelineId}/${pipelineVersionId}/view`);
this.wait();
}

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

selectPipelineVersionByName(name: string): void {
this.findPipelineVersionSelect()
this.pipelineVersionSelector
.findToggleButton()
.click()
.parents()
.findByTestId('pipeline-version-selector-table-list')
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/__tests__/cypress/cypress/pages/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class ProjectDetails {
);
}

findImportPipelineButton(timeout?: undefined) {
findImportPipelineButton(timeout?: number) {
return cy.findByTestId('import-pipeline-button', { timeout });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('An admin user can import and run a pipeline', { testIsolation: false }
pipelineDetails.selectActionDropdownItem('Create run');

//Fill the Create run fields
createRunPage.findExperimentSelect().click();
createRunPage.experimentSelect.findToggleButton().click();
createRunPage.selectExperimentByName('Default');
createRunPage.fillName(testRunName);
createRunPage.fillDescription('Run Description');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ describe('Distributed Workload Metrics root page', () => {
globalDistributedWorkloads.visit();
cy.url().should('include', '/projectMetrics/test-project');

globalDistributedWorkloads.selectProjectByName('Test Project 2');
globalDistributedWorkloads.projectDropdown.selectItem('Test Project 2');
cy.url().should('include', '/projectMetrics/test-project-2');

cy.findByLabelText('Distributed workload status tab').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ describe('Register model page', () => {
registerModelPage
.findConnectionSelector()
.contains('Select a project to view its available data connections');
registerModelPage.findProjectSelector().findDropdownItem('Test Project').click();
registerModelPage.projectDropdown.selectItem('Test Project');
registerModelPage.findConnectionSelector().contains('No available data connections');
});

Expand All @@ -150,7 +150,7 @@ describe('Register model page', () => {
registerModelPage
.findConnectionSelector()
.contains('Select a project to view its available data connections');
registerModelPage.findProjectSelector().findDropdownItem('Test Project').click();
registerModelPage.projectDropdown.selectItem('Test Project');
registerModelPage.findConnectionSelector().contains('Select data connection');
registerModelPage.findConnectionSelector().findDropdownItem('Test Secret').click();
registerModelPage.findAutofillButton().click();
Expand Down
Loading

0 comments on commit 4a6ab8a

Please sign in to comment.