From c453c341de63b7caa464d7bef796e09561f9ff70 Mon Sep 17 00:00:00 2001 From: Ashton Galloway Date: Wed, 30 Oct 2024 16:02:24 -0400 Subject: [PATCH 1/2] test: add experiment list test for stop row action This adds an experiment list test for the stop action. it also introduces a new test fixture to allow for creating new experiments to be cleaned up afterwards on the fly. --- .../src/e2e/fixtures/api.project.fixture.ts | 31 +++++++++-------- .../src/e2e/fixtures/api.search.fixture.ts | 4 +-- .../src/e2e/tests/experimentList.spec.ts | 33 +++++++++++++++++++ 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/webui/react/src/e2e/fixtures/api.project.fixture.ts b/webui/react/src/e2e/fixtures/api.project.fixture.ts index 6a4bade3e4d..2c9d769d10d 100644 --- a/webui/react/src/e2e/fixtures/api.project.fixture.ts +++ b/webui/react/src/e2e/fixtures/api.project.fixture.ts @@ -52,22 +52,25 @@ export class ApiProjectFixture extends apiFixture(ProjectsApi) { * @param {number} id The id of the project. */ async deleteProject(id: number): Promise { + try { + await this.api.deleteProject(id); + } catch (error) { + if (error instanceof Response && error.body) { + const bodyText = error.text(); + throw new Error( + `Delete Project Request failed. Status: ${error.status} Request: ${JSON.stringify({ + id, + })} Response: ${bodyText}`, + ); + } + } await expect .poll( - async () => { - const projectResp = await this.api.deleteProject(id).catch(async function (error) { - const respBody = await streamConsumers.text(error.body); - if (error.status === 404) { - return { completed: true }; - } - throw new Error( - `Delete Project Request failed. Status: ${error.status} Request: ${JSON.stringify( - id, - )} Response: ${respBody}`, - ); - }); - return projectResp.completed; - }, + () => + this.api + .getProject(id) + .then(() => false) + .catch((res) => res.status === 404), { message: `Delete Project Request failed ${JSON.stringify(id)}`, timeout: 15_000, diff --git a/webui/react/src/e2e/fixtures/api.search.fixture.ts b/webui/react/src/e2e/fixtures/api.search.fixture.ts index 7572363fd15..43b850e448c 100644 --- a/webui/react/src/e2e/fixtures/api.search.fixture.ts +++ b/webui/react/src/e2e/fixtures/api.search.fixture.ts @@ -211,9 +211,9 @@ export class ApiSearchFixture extends apiFixture(InternalApi) { entrypoint: 'echo bonjour!', name: safeName('apisearch'), searcher: { + max_trials: 1, metric: 'x', - name: 'custom', - unit: 'batches', + name: 'random', }, ...config, }; diff --git a/webui/react/src/e2e/tests/experimentList.spec.ts b/webui/react/src/e2e/tests/experimentList.spec.ts index 8ae7f66d01a..ee69ce4b613 100644 --- a/webui/react/src/e2e/tests/experimentList.spec.ts +++ b/webui/react/src/e2e/tests/experimentList.spec.ts @@ -327,6 +327,7 @@ test.describe('Experiment List', () => { await waitTableStable(); await expect.soft((await row.getCellByColumnName('Name')).pwLocator).toHaveText(editedValue); }); + // await test.step('Stop', async () => { // // what happens if the experiment is already stopped? // }); @@ -346,6 +347,38 @@ test.describe('Experiment List', () => { // await test.step('Hyperparameter Search', async () => {}); }); + test('DataGrid Action Stop', async ({ apiSearches, newProject }) => { + const search = await apiSearches.new({}, { projectId: newProject.response.project.id }); + await test.step('filter to experiment', async () => { + const tableFilter = + await projectDetailsPage.f_experimentList.tableActionBar.tableFilter.open(); + await tableFilter.filterForm.filter.filterFields.columnName.selectMenuOption('ID'); + await tableFilter.filterForm.filter.filterFields.operator.selectMenuOption('='); + await tableFilter.filterForm.filter.filterFields.valueNumber.pwLocator.fill( + search.id.toString(), + ); + + await expect(projectDetailsPage.f_experimentList.tableActionBar.count.pwLocator).toHaveText( + /^1 /, + ); + await tableFilter.close(); + }); + await test.step('stop experiment', async () => { + const row = projectDetailsPage.f_experimentList.dataGrid.getRowByIndex(0); + await row.experimentActionDropdown.open(); + await row.experimentActionDropdown.pwLocator.getByRole('menuitem', { name: 'Stop' }).click(); + await expect((await row.getCellByColumnName('State')).pwLocator).toHaveText('canceled'); + }); + await test.step('stop menu item should be gone', async () => { + const row = projectDetailsPage.f_experimentList.dataGrid.getRowByIndex(0); + await row.experimentActionDropdown.open(); + await expect(row.experimentActionDropdown.pwLocator).toBeVisible(); + await expect( + row.experimentActionDropdown.pwLocator.getByRole('menuitem', { name: 'Stop' }), + ).toHaveCount(0); + }); + }); + test('DataGrid Action Pause', async () => { // datagrid can be slow, perhaps related to [ET-677] projectDetailsPage._page.setDefaultTimeout(10000); From 723e94c0412cfb5b51546132d2fbc1e75bb19ef3 Mon Sep 17 00:00:00 2001 From: Ashton Galloway Date: Fri, 1 Nov 2024 13:52:32 -0400 Subject: [PATCH 2/2] deleteProject sometimes does return 404 and sometimes doesn't :shrug: --- webui/react/src/e2e/fixtures/api.project.fixture.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webui/react/src/e2e/fixtures/api.project.fixture.ts b/webui/react/src/e2e/fixtures/api.project.fixture.ts index 2c9d769d10d..2f428906648 100644 --- a/webui/react/src/e2e/fixtures/api.project.fixture.ts +++ b/webui/react/src/e2e/fixtures/api.project.fixture.ts @@ -56,6 +56,9 @@ export class ApiProjectFixture extends apiFixture(ProjectsApi) { await this.api.deleteProject(id); } catch (error) { if (error instanceof Response && error.body) { + if (error.status === 404) { + return; + } const bodyText = error.text(); throw new Error( `Delete Project Request failed. Status: ${error.status} Request: ${JSON.stringify({