Skip to content
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
@@ -0,0 +1,22 @@
projectName: 'mlflow-exp-test'
experiments:
- name: 'e2e-test-experiment'
renamedName: 'e2e-renamed-experiment'
- name: 'e2e-compare-experiment'
renamedName: 'e2e-compare-experiment-renamed'
runs:
- name: 'e2e-test-run-1'
parameters:
learning_rate: '0.01'
batch_size: '32'
metrics:
accuracy: '0.95'
loss: '0.05'
- name: 'e2e-test-run-2'
parameters:
learning_rate: '0.001'
batch_size: '64'
metrics:
accuracy: '0.97'
loss: '0.03'
nonExistentExperiment: 'nonexistent-experiment-xyz-no-results'
8 changes: 8 additions & 0 deletions packages/cypress/cypress/pages/appChrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ class AppChrome {
findNavItem(args: { name: string; rootSection?: string; subSection?: string }) {
return this.findSideBar().findAppNavItem(args);
}

findDarkThemeToggle() {
return cy.findByTestId('dark-theme-toggle');
}

findLightThemeToggle() {
return cy.findByTestId('light-theme-toggle');
}
}

export const appChrome = new AppChrome();
215 changes: 215 additions & 0 deletions packages/cypress/cypress/pages/mlflowExperiments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import { appChrome } from './appChrome';

export enum ExperimentTypeToggle {
GEN_AI = 'GenAI',
MODEL_TRAINING = 'Model training',
}

const MLFLOW_DARK_MODE_KEY = '_mlflow_dark_mode_toggle_enabled';
const EXPERIMENTS_PATH = '/develop-train/mlflow/experiments';

class MlflowExperiments {
visit(workspace?: string) {
const qs = workspace ? `?workspace=${workspace}` : '';
cy.visitWithLogin(`${EXPERIMENTS_PATH}${qs}`);
this.wait();
}

navigate() {
this.findNavItem().click();
this.wait();
}

private wait() {
cy.findByTestId('app-page-title', { timeout: 30000 }).should('exist');
cy.testA11y();
}

waitForEmbeddedContent() {
this.findExperimentsSearchInput().should('be.visible');
}

shouldHaveExperimentsUrl() {
cy.url().should('include', EXPERIMENTS_PATH).should('include', 'workspace=');
}

shouldHaveWorkspace(workspace: string) {
cy.url().should('include', `workspace=${workspace}`);
}

findNavItem() {
return appChrome.findNavItem({
name: 'Experiments (MLflow)',
rootSection: 'Develop & train',
});
}

findNavSection() {
return appChrome.findNavSection('Develop & train');
}

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

findLaunchMlflowButton() {
return cy.findByTestId('mlflow-embedded-jump-link', { timeout: 10000 });
}

findMlflowUnavailableState() {
return cy.findByTestId('mlflow-unavailable-empty-state');
}

findErrorEmptyState() {
return cy.findByTestId('empty-state-title', { timeout: 10000 });
}

findProjectSelector() {
return cy.findByTestId('project-selector-toggle', { timeout: 30000 });
}

findProjectInDropdown(name: string) {
return cy.findByRole('menuitem', { name });
}

findBreadcrumb() {
return cy.findByRole('navigation', { name: 'Breadcrumb' });
}

findBreadcrumbItem(label: string) {
return this.findBreadcrumb().contains(label);
}

findExperimentTypeToggleItem(label: string) {
return cy.contains('[role="button"][aria-pressed]', label);
}

shouldHaveExperimentTypeSelected(label: string) {
this.findExperimentTypeToggleItem(label).should('have.attr', 'aria-pressed', 'true');
}

findUsageTab() {
return cy.findByRole('tab', { name: 'Usage' });
}

findQualityTab() {
return cy.findByRole('tab', { name: 'Quality' });
}

findToolCallsTab() {
return cy.findByRole('tab', { name: 'Tool calls' });
}

shouldHaveUsageTabSelected() {
this.findUsageTab().should('have.attr', 'aria-selected', 'true');
}

findEvaluationRunsLink() {
return cy.findByRole('link', { name: 'Evaluation runs' });
}

findExperimentsSearchInput() {
return cy.findByTestId('search-experiment-input', { timeout: 30000 });
}

findCreateExperimentButton() {
return cy.findByTestId('create-experiment-table-empty-state-button', { timeout: 30000 });
}

findExperimentInTable(name: string) {
return cy.findByRole('link', { name });
}

findCreateExperimentModal() {
return cy.findByTestId('mlflow-input-modal');
}

findExperimentNameInput() {
return this.findCreateExperimentModal().find('input').first();
}

findCreateDialogSubmitButton() {
return this.findCreateExperimentModal().findByRole('button', { name: 'Create' });
}

findExperimentDetailHeading(name: string) {
return cy.findByRole('heading', { name, timeout: 10000 });
}

findOverflowMenuTrigger() {
return cy.findByTestId('overflow-menu-trigger');
}

findRenameAction() {
return cy.findByTestId('rename');
}

findDeleteAction() {
return cy.findByTestId('delete');
}

findRenameInput() {
return this.findCreateExperimentModal().find('input').first();
}

findRenameSubmitButton() {
return this.findCreateExperimentModal().findByRole('button', { name: 'Save' });
}

findDeleteConfirmModal() {
return cy.findByTestId('confirm-modal');
}

findDeleteConfirmButton() {
return this.findDeleteConfirmModal().findByRole('button', { name: 'Delete' });
}

shouldHaveRunsTable() {
cy.findByTestId('sort-header-Run Name', { timeout: 10000 }).should('exist');
}

findRunInTable(runName: string) {
return cy.contains('[role="row"]', runName);
}

findRunCheckbox(runName: string) {
return this.findRunInTable(runName).find('[role="checkbox"], input[type="checkbox"]').first();
}

findCompareButton() {
return cy.findByRole('button', { name: /compare/i });
}

findCompareRunsHeading() {
return cy.contains('Comparing');
}

findCompareRunsVisualizations() {
return cy.contains('Visualizations');
}

findCompareRunDetails() {
return cy.contains('Run details');
}

shouldContainText(text: string) {
cy.contains(text).should('be.visible');
}

findRunParameters() {
return cy.contains('Parameters', { timeout: 10000 });
}

findRunMetrics() {
return cy.contains('Metrics', { timeout: 10000 });
}

getMlflowDarkModeStorageValue(): Cypress.Chainable<string | null> {
return cy.window().then((win) => {
const value = win.localStorage.getItem(MLFLOW_DARK_MODE_KEY);
return cy.wrap<string | null>(value);
});
}
}

export const mlflowExperiments = new MlflowExperiments();
26 changes: 13 additions & 13 deletions packages/cypress/cypress/pages/promptManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,19 @@ class PromptManagement {
}

findProjectSelector() {
return cy.findByTestId('project-selector-dropdown');
return cy.findByTestId('project-selector-toggle', { timeout: 30000 });
}

findProjectInDropdown(name: string) {
return cy.findByRole('menuitem', { name });
}

shouldHaveWorkspace(workspace: string) {
cy.url().should('include', `workspace=${workspace}`);
}

findErrorEmptyState() {
return cy.findByTestId('empty-state-title', { timeout: 10000 });
}

findPromptsSearchInput() {
Expand Down Expand Up @@ -93,24 +105,12 @@ class PromptManagement {
return cy.findByRole('radio', { name: 'Preview' });
}

findDarkThemeToggle() {
return cy.findByTestId('dark-theme-toggle');
}

findLightThemeToggle() {
return cy.findByTestId('light-theme-toggle');
}

getMlflowDarkModeStorageValue(): Cypress.Chainable<string | null> {
return cy.window().then((win) => {
const value = win.localStorage.getItem(MLFLOW_DARK_MODE_KEY);
return cy.wrap<string | null>(value);
});
}

getHtmlDarkModeClass(): Cypress.Chainable<boolean> {
return cy.document().then((doc) => doc.documentElement.classList.contains('pf-v6-theme-dark'));
}
}

export const promptManagement = new PromptManagement();
Loading
Loading