Skip to content

Commit

Permalink
Shared scheduling MVP (#1149)
Browse files Browse the repository at this point in the history
* split scheduling into metadata and definition
* added AssociationForm and DefinitionEditor components
* order analyses by descending id
* fix editors not loading in preselected models on page load
* filter out scheduling items that are private
* make constraints/scheduling columns 50/50

---------

Co-authored-by: Aaron Plave <[email protected]>
  • Loading branch information
duranb and AaronPlave authored Mar 20, 2024
1 parent 85b7de7 commit d25af7b
Show file tree
Hide file tree
Showing 51 changed files with 4,518 additions and 2,800 deletions.
4 changes: 2 additions & 2 deletions e2e-tests/fixtures/Constraints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ export class Constraints {
this.confirmModal = page.locator(`.modal:has-text("Delete Constraint")`);
this.confirmModalDeleteButton = page.locator(`.modal:has-text("Delete Constraint") >> button:has-text("Delete")`);
this.inputConstraintDefinition = page.locator('.monaco-editor >> textarea.inputarea');
this.inputConstraintDescription = page.locator('textarea[name="constraint-description"]');
this.inputConstraintDescription = page.locator('textarea[name="metadata-description"]');
this.inputConstraintModel = page.locator(this.inputConstraintModelSelector);
this.inputConstraintName = page.locator('input[name="constraint-name"]');
this.inputConstraintName = page.locator('input[name="metadata-name"]');
this.page = page;
this.saveButton = page.locator(`button:has-text("Save")`);
this.tableRow = page.locator(`.ag-row:has-text("${this.constraintName}")`);
Expand Down
21 changes: 19 additions & 2 deletions e2e-tests/fixtures/Plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ export class Plan {
scheduleButton: Locator;
schedulingConditionEnabledCheckbox: Locator;
schedulingConditionListItemSelector: string;
schedulingConditionManageButton: Locator;
schedulingConditionNewButton: Locator;
schedulingGoal: Locator;
schedulingGoalDifferenceBadge: Locator;
schedulingGoalEnabledCheckboxSelector: (goalName: string) => Locator;
schedulingGoalExpand: Locator;
schedulingGoalListItemSelector: (goalName: string) => string;
schedulingGoalManageButton: Locator;
schedulingGoalNewButton: Locator;
schedulingSatisfiedActivity: Locator;
schedulingStatusSelector: (status: string) => string;
Expand Down Expand Up @@ -91,28 +93,34 @@ export class Plan {
}

async createSchedulingCondition(baseURL: string | undefined) {
await this.schedulingConditionManageButton.click();
const [newSchedulingConditionPage] = await Promise.all([
this.page.waitForEvent('popup'),
this.schedulingConditionNewButton.click(),
]);
this.schedulingConditions.updatePage(newSchedulingConditionPage);
await newSchedulingConditionPage.waitForURL(`${baseURL}/scheduling/conditions/new?modelId=*&&specId=*`);
await newSchedulingConditionPage.waitForURL(`${baseURL}/scheduling/conditions/new?modelId=*`);
await this.schedulingConditions.createSchedulingCondition(baseURL);
await newSchedulingConditionPage.close();
this.schedulingConditions.updatePage(this.page);
await this.page.getByRole('row', { name: this.schedulingConditions.conditionName }).getByRole('checkbox').click();
await this.page.getByRole('button', { name: 'Update' }).click();
await this.page.waitForSelector(this.schedulingConditionListItemSelector, { state: 'visible', strict: true });
}

async createSchedulingGoal(baseURL: string | undefined, goalName: string) {
await this.schedulingGoalManageButton.click();
const [newSchedulingGoalPage] = await Promise.all([
this.page.waitForEvent('popup'),
this.schedulingGoalNewButton.click(),
]);
this.schedulingGoals.updatePage(newSchedulingGoalPage);
await newSchedulingGoalPage.waitForURL(`${baseURL}/scheduling/goals/new?modelId=*&&specId=*`);
await newSchedulingGoalPage.waitForURL(`${baseURL}/scheduling/goals/new?modelId=*`);
await this.schedulingGoals.createSchedulingGoal(baseURL, goalName);
await newSchedulingGoalPage.close();
this.schedulingGoals.updatePage(this.page);
await this.page.getByRole('row', { name: goalName }).getByRole('checkbox').click();
await this.page.getByRole('button', { name: 'Update' }).click();
await this.page.waitForSelector(this.schedulingGoalListItemSelector(goalName), { state: 'visible', strict: true });
}

Expand Down Expand Up @@ -165,6 +173,13 @@ export class Plan {
await this.page.locator(this.constraintListItemSelector).waitFor({ state: 'detached' });
}

async removeSchedulingGoal(goalName: string) {
await this.schedulingGoalManageButton.click();
await this.page.getByRole('row', { name: goalName }).getByRole('checkbox').click();
await this.page.getByRole('button', { name: 'Update' }).click();
await this.page.locator(this.schedulingGoalListItemSelector(goalName)).waitFor({ state: 'detached' });
}

async runAnalysis() {
await this.analyzeButton.click();
await this.waitForSchedulingStatus('Incomplete');
Expand Down Expand Up @@ -330,6 +345,8 @@ export class Plan {
this.roleSelector = page.locator(`.nav select`);
this.scheduleButton = page.locator('.header-actions button[aria-label="Schedule"]');
this.analyzeButton = page.locator('.header-actions button[aria-label="Analyze"]');
this.schedulingGoalManageButton = page.locator(`button[name="manage-goals"]`);
this.schedulingConditionManageButton = page.locator(`button[name="manage-conditions"]`);
this.schedulingGoal = page.locator('.scheduling-goal').first();
this.schedulingGoalDifferenceBadge = this.schedulingGoal.locator('.difference-badge');
this.schedulingGoalEnabledCheckboxSelector = (goalName: string) =>
Expand Down
16 changes: 2 additions & 14 deletions e2e-tests/fixtures/SchedulingConditions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { adjectives, animals, colors, uniqueNamesGenerator } from 'unique-names-generator';
import { fillEditorText } from '../utilities/editor.js';
import { getOptionValueFromText } from '../utilities/selectors.js';
import { Models } from './Models.js';

export class SchedulingConditions {
Expand All @@ -28,14 +27,12 @@ export class SchedulingConditions {

async createSchedulingCondition(baseURL: string | undefined) {
await expect(this.saveButton).toBeDisabled();
await this.selectModel();
await this.fillConditionName();
await this.fillConditionDescription();
await this.fillConditionDefinition();
await expect(this.saveButton).not.toBeDisabled();
await this.saveButton.click();
await this.page.waitForURL(`${baseURL}/scheduling/conditions/edit/*`);
await expect(this.saveButton).not.toBeDisabled();
await expect(this.closeButton).not.toBeDisabled();
await this.closeButton.click();
await this.page.waitForURL(`${baseURL}/scheduling`);
Expand All @@ -45,7 +42,6 @@ export class SchedulingConditions {
await this.goto();
await expect(this.tableRow).toBeVisible();
await expect(this.tableRowDeleteButton).not.toBeVisible();

await this.tableRow.hover();
await this.tableRowDeleteButton.waitFor({ state: 'attached' });
await this.tableRowDeleteButton.waitFor({ state: 'visible' });
Expand Down Expand Up @@ -86,24 +82,16 @@ export class SchedulingConditions {
await this.page.waitForSelector(`input[placeholder="Filter conditions"]`, { state: 'attached' });
}

async selectModel() {
await this.page.waitForSelector(`option:has-text("${this.models.modelName}")`, { state: 'attached' });
const value = await getOptionValueFromText(this.page, this.inputConditionModelSelector, this.models.modelName);
await this.inputConditionModel.focus();
await this.inputConditionModel.selectOption(value);
await this.inputConditionModel.evaluate(e => e.blur());
}

updatePage(page: Page): void {
this.closeButton = page.locator(`button:has-text("Close")`);
this.confirmModal = page.locator(`.modal:has-text("Delete Scheduling Condition")`);
this.confirmModalDeleteButton = page.locator(
`.modal:has-text("Delete Scheduling Condition") >> button:has-text("Delete")`,
);
this.inputConditionDefinition = page.locator('.monaco-editor >> textarea.inputarea');
this.inputConditionDescription = page.locator('textarea[name="condition-description"]');
this.inputConditionDescription = page.locator('textarea[name="metadata-description"]');
this.inputConditionModel = page.locator(this.inputConditionModelSelector);
this.inputConditionName = page.locator(`input[name="condition-name"]`);
this.inputConditionName = page.locator(`input[name="metadata-name"]`);
this.newButton = page.locator(`button:has-text("New")`);
this.page = page;
this.saveButton = page.locator(`button:has-text("Save")`);
Expand Down
15 changes: 2 additions & 13 deletions e2e-tests/fixtures/SchedulingGoals.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { expect, type Locator, type Page } from '@playwright/test';
import { fillEditorText } from '../utilities/editor.js';
import { getOptionValueFromText } from '../utilities/selectors.js';
import { Models } from './Models.js';

export class SchedulingGoals {
Expand All @@ -25,14 +24,12 @@ export class SchedulingGoals {

async createSchedulingGoal(baseURL: string | undefined, goalName: string) {
await expect(this.saveButton).toBeDisabled();
await this.selectModel();
await this.fillGoalName(goalName);
await this.fillGoalDescription();
await this.fillGoalDefinition();
await expect(this.saveButton).not.toBeDisabled();
await this.saveButton.click();
await this.page.waitForURL(`${baseURL}/scheduling/goals/edit/*`);
await expect(this.saveButton).not.toBeDisabled();
await expect(this.closeButton).not.toBeDisabled();
await this.closeButton.click();
await this.page.waitForURL(`${baseURL}/scheduling`);
Expand Down Expand Up @@ -83,24 +80,16 @@ export class SchedulingGoals {
await this.page.waitForSelector(`input[placeholder="Filter goals"]`, { state: 'attached' });
}

async selectModel() {
await this.page.waitForSelector(`option:has-text("${this.models.modelName}")`, { state: 'attached' });
const value = await getOptionValueFromText(this.page, this.inputGoalModelSelector, this.models.modelName);
await this.inputGoalModel.focus();
await this.inputGoalModel.selectOption(value);
await this.inputGoalModel.evaluate(e => e.blur());
}

updatePage(page: Page): void {
this.closeButton = page.locator(`button:has-text("Close")`);
this.confirmModal = page.locator(`.modal:has-text("Delete Scheduling Goal")`);
this.confirmModalDeleteButton = page.locator(
`.modal:has-text("Delete Scheduling Goal") >> button:has-text("Delete")`,
);
this.inputGoalDefinition = page.locator('.monaco-editor >> textarea.inputarea');
this.inputGoalDescription = page.locator('textarea[name="goal-description"]');
this.inputGoalDescription = page.locator('textarea[name="metadata-description"]');
this.inputGoalModel = page.locator(this.inputGoalModelSelector);
this.inputGoalName = page.locator(`input[name="goal-name"]`);
this.inputGoalName = page.locator(`input[name="metadata-name"]`);
this.newButton = page.locator(`button:has-text("New")`);
this.page = page;
this.saveButton = page.locator(`button:has-text("Save")`);
Expand Down
1 change: 1 addition & 0 deletions e2e-tests/tests/scheduling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ test.describe.serial('Scheduling', () => {
});

test('Delete scheduling goal', async () => {
await plan.removeSchedulingGoal(goalName1);
await schedulingGoals.deleteSchedulingGoal(goalName1);
});
});
Loading

0 comments on commit d25af7b

Please sign in to comment.