-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add basic test for runs (no experiments selected) * Add test for selected generated experiment * Update playwright dev dependency for local execution * Test navigating from table to experiment page * Test navigating from dashboard to runs * Clean up tests * Test navigation to run page on clicking run name * Test that run page param searchbox works * Test metrics explorer link query content * Test Run settings page description/name editing * Test that run selector is working * Fix run selector test (force alphabetical ordering) * Improve formatting and comments
- Loading branch information
Showing
4 changed files
with
264 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import { expect, test } from '@playwright/test'; | ||
|
||
const BASE_URL = 'http://localhost:3000/aim'; | ||
const RUNS_PAGE = `${BASE_URL}/runs`; | ||
|
||
test.describe('Individual Run Page', () => { | ||
// Navigate to the run page before each test as the link's hash is unknown | ||
test.beforeEach(async ({ page }) => { | ||
await page.goto(RUNS_PAGE); | ||
await page.waitForLoadState('networkidle'); | ||
await page.click( | ||
'.ExperimentBar__headerContainer__appBarTitleBox__buttonSelectToggler', | ||
); | ||
|
||
const button = page.locator('button', { hasText: /^experiment-/ }); | ||
await button.click(); | ||
await page.waitForSelector('.Table__cell.undefined.experiment'); | ||
await page.mouse.click(0, 0); | ||
await page.waitForSelector('.RunsTable'); | ||
const runNameLinks = page.locator( | ||
'.Table__cell.undefined.run .RunNameColumn__runName a', | ||
); | ||
|
||
// Get the first run's link in alphabetical order and click on it | ||
const runNameTexts = await runNameLinks.allTextContents(); | ||
const sortedRunNames = runNameTexts | ||
.slice() | ||
.sort((a, b) => a.localeCompare(b)); | ||
|
||
const firstRunNameIndex = runNameTexts.indexOf(sortedRunNames[0]); | ||
const firstRunNameLink = runNameLinks.nth(firstRunNameIndex); | ||
|
||
await firstRunNameLink.click(); | ||
await page.waitForURL(/\/aim\/runs\/.+/); | ||
}); | ||
|
||
test('run params search box is working', async ({ page }) => { | ||
await page.fill('input[name="search"]', 'param1'); | ||
|
||
await page.waitForSelector('div[role="row"]'); | ||
|
||
const row = await page.$eval('div[role="row"]', (row) => row.textContent); | ||
|
||
expect(row).not.toBeNull(); | ||
expect(row).toMatch(/param1"(\d+\.\d+)"/); | ||
|
||
const rows = await page.$$eval('div[role="row"]', (rows) => | ||
rows.map((row) => row.textContent), | ||
); | ||
expect(rows[0]).toContain('param1'); | ||
expect(rows.length).toBe(2); // 1 entry plus the header | ||
}); | ||
|
||
test('view in metrics explorer link queries the right hash', async ({ | ||
page, | ||
}) => { | ||
// Wait for page content to load first | ||
await page.waitForSelector('.runHashListItem__hashWrapper .Text'); | ||
const hash = await page.$eval( | ||
'.runHashListItem__hashWrapper .Text', | ||
(element) => element.textContent?.trim(), | ||
); | ||
|
||
await page.click('a:has-text("View in Metrics Explorer")', { force: true }); | ||
|
||
await page.waitForSelector('.view-lines.monaco-mouse-cursor-text'); | ||
const textBox = page.locator('.view-lines.monaco-mouse-cursor-text'); | ||
|
||
const textContent = await textBox.evaluate((el) => el.innerText); | ||
|
||
// Remove tabs and newlines that might be present in the text content | ||
const trimmedTextContent = textContent.replace(/\s/g, ''); | ||
|
||
expect(trimmedTextContent).toContain(hash); | ||
}); | ||
|
||
test('settings page name and description can be edited', async ({ page }) => { | ||
await page.click( | ||
'.RunDetail__runDetailContainer__appBarContainer__appBarBox__actionContainer button', | ||
); | ||
await page.waitForSelector('.RunDetailSettingsTab'); | ||
|
||
const nameInput = page.locator( | ||
'.NameAndDescriptionCard__content__nameBox__nameInput input', | ||
); | ||
await nameInput.fill('New Run Name'); | ||
|
||
const descriptionInput = page | ||
.locator( | ||
'.NameAndDescriptionCard__content__descriptionBox__descriptionInput textarea', | ||
) | ||
.first(); | ||
await descriptionInput.fill('New Run Description'); | ||
|
||
await page.click('.NameAndDescriptionCard__saveBtn', { force: true }); | ||
}); | ||
|
||
test('run selector is working', async ({ page }) => { | ||
const runNameElement = page.locator( | ||
'.RunDetail__runDetailContainer__appBarContainer__appBarTitleBox__runName', | ||
); | ||
|
||
const originalRunName = await runNameElement.innerText(); | ||
|
||
await page.click( | ||
'.RunDetail__runDetailContainer__appBarContainer__appBarTitleBox__buttonSelectToggler', | ||
{ force: true }, | ||
); | ||
|
||
// Wait for the runs list to appear | ||
await page.waitForSelector( | ||
'div.RunSelectPopoverWrapper__selectPopoverContent__contentContainer__runsListContainer__runsList', | ||
); | ||
|
||
const runLocator = page.locator( | ||
'a.RunSelectPopoverWrapper__selectPopoverContent__contentContainer__runsListContainer__runsList__runBox', | ||
); | ||
|
||
// Get the last run name in alphabetical order and click on it | ||
const runNameElements = await runLocator.elementHandles(); | ||
const runNames = await Promise.all( | ||
runNameElements.map((element) => element.innerText()), | ||
); | ||
const sortedRunNames = runNames.slice().sort((a, b) => a.localeCompare(b)); | ||
const lastRunNameIndex = runNames.indexOf( | ||
sortedRunNames[sortedRunNames.length - 1], | ||
); | ||
|
||
const lastRunNameLink = runLocator.nth(lastRunNameIndex); | ||
await lastRunNameLink.click({ force: true }); | ||
|
||
// Click outside the popover to close it | ||
await page.mouse.click(0, 0); | ||
|
||
const newRunName = await runNameElement.innerText(); | ||
expect(newRunName).not.toBe(originalRunName); | ||
}); | ||
|
||
test.afterEach(async ({ page }, testInfo) => { | ||
if (testInfo.status !== testInfo.expectedStatus) { | ||
await page.screenshot({ path: `failed-${testInfo.title}.png` }); | ||
} | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { test, expect } from '@playwright/test'; | ||
|
||
const BASE_URL = 'http://localhost:3000/aim'; | ||
const RUNS_PAGE = `${BASE_URL}/runs`; | ||
|
||
test.describe('Runs Explorer', () => { | ||
test.beforeEach(async ({ page }) => { | ||
await page.goto(RUNS_PAGE); | ||
await page.waitForLoadState('networkidle'); | ||
}); | ||
|
||
test('navigates correctly from dashboard', async ({ page }) => { | ||
await page.goto(BASE_URL); | ||
await page.waitForLoadState('networkidle'); | ||
await page.click('text=Runs'); | ||
await page.waitForLoadState('networkidle'); | ||
expect(page.url()).toBe(RUNS_PAGE); | ||
}); | ||
|
||
test('displays no results message when no experiments are selected', async ({ | ||
page, | ||
}) => { | ||
const runsTable = page.locator('.RunsTable'); | ||
expect(await runsTable.locator('text=No results').count()).toBe(1); | ||
}); | ||
|
||
test('has two runs if generated experiment is selected', async ({ page }) => { | ||
// Add the generated experiment to the selection and wait for the table to appear | ||
await page.click( | ||
'.ExperimentBar__headerContainer__appBarTitleBox__buttonSelectToggler', | ||
); | ||
|
||
const button = page.locator('button', { hasText: /^experiment-/ }); | ||
await button.click(); | ||
|
||
await page.waitForSelector('.Table__cell.undefined.experiment'); | ||
|
||
const rows = page.locator( | ||
'.Table__cell.undefined.experiment .ExperimentNameBox__experimentName', | ||
); | ||
|
||
expect(await rows.count()).toBe(2); | ||
|
||
for (let i = 0; i < 2; i++) { | ||
const runName = await rows.nth(i).innerText(); | ||
expect(runName).toMatch(/^experiment-/); | ||
} | ||
}); | ||
|
||
test('clicking on the experiment name navigates to the experiment page', async ({ | ||
page, | ||
}) => { | ||
await page.click( | ||
'.ExperimentBar__headerContainer__appBarTitleBox__buttonSelectToggler', | ||
); | ||
|
||
const button = page.locator('button', { hasText: /^experiment-/ }); | ||
await button.click(); | ||
|
||
await page.waitForSelector('.Table__cell.undefined.experiment'); | ||
|
||
// Click on a random part of the screen to close the popover | ||
await page.mouse.click(0, 0); | ||
|
||
const rows = page.locator( | ||
'.Table__cell.undefined.experiment .ExperimentNameBox__experimentName', | ||
); | ||
|
||
await rows | ||
.locator('a', { hasText: /^experiment-/ }) | ||
.first() | ||
.click(); | ||
|
||
await page.waitForURL(/\/aim\/experiments\/\d+\/overview/); | ||
expect(page.url()).toMatch(/\/aim\/experiments\/\d+\/overview/); | ||
}); | ||
|
||
test("clicking on the first run name navigates to that run's page", async ({ | ||
page, | ||
}) => { | ||
await page.click( | ||
'.ExperimentBar__headerContainer__appBarTitleBox__buttonSelectToggler', | ||
); | ||
|
||
const button = page.locator('button', { hasText: /^experiment-/ }); | ||
await button.click(); | ||
|
||
await page.waitForSelector('.Table__cell.undefined.experiment'); | ||
|
||
await page.mouse.click(0, 0); | ||
|
||
await page.waitForSelector('.RunsTable'); | ||
|
||
const firstRunNameLink = page | ||
.locator('.Table__cell.undefined.run .RunNameColumn__runName a') | ||
.first(); | ||
|
||
await firstRunNameLink.click(); | ||
|
||
await page.waitForURL(/\/aim\/runs\/.+/); | ||
expect(page.url()).toMatch(/\/aim\/runs\/.+/); | ||
}); | ||
|
||
test.afterEach(async ({ page }, testInfo) => { | ||
if (testInfo.status !== testInfo.expectedStatus) { | ||
await page.screenshot({ path: `failed-${testInfo.title}.png` }); | ||
} | ||
}); | ||
}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters