-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SWC-6605 #5235
SWC-6605 #5235
Conversation
…kipped when previous job was skipped
…slow network requests, increase timeout at key steps with known slow responses, decrease expect timeout when using page reloads
…un and number of runners used due to GitHub restricting number of concurrent macOS jobs
# and on all branches in user-owned forks | ||
if: ${{ github.ref_name == 'develop' || startsWith(github.ref_name, 'release-') || github.actor == github.repository_owner }} | ||
if: ${{ startsWith(github.ref_name, 'release-') || github.actor == github.repository_owner }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only run e2e workflow for release-**
branches in Sage repo, so macOS runners are available for other teams' workflows
@@ -25,9 +25,10 @@ jobs: | |||
retention-days: 1 | |||
playwright-tests: | |||
needs: [build] | |||
runs-on: ${{ github.repository_owner == 'Sage-Bionetworks' && 'ubuntu-22.04-4core-16GBRAM-150GBSSD' || 'macos-latest' }} | |||
runs-on: 'macos-latest' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use macOS runner for all jobs to decrease flakiness vs linux runners -- see 10x passing runs using macOS runner here.
timeout-minutes: 60 | ||
strategy: | ||
max-parallel: ${{ github.repository_owner == 'Sage-Bionetworks' && 1 || 3 }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only run one shard at a time in the Sage repo, so macOS runners are available for other teams' workflows
# But skip this job if the previous job was cancelled or skipped | ||
if: ${{ !cancelled() && needs.playwright-tests.result != 'skipped' }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"skipped" !== "cancelled" -- skip the job if the workflow was "skipped", as in this case.
@@ -58,38 +61,6 @@ const expectThreadTableLoaded = async ( | |||
}) | |||
} | |||
|
|||
const expectDiscussionThreadLoaded = async ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved into testUser.ts
, so this can be reused in other tests
@@ -153,6 +126,7 @@ test.describe('Discussions', () => { | |||
}) | |||
|
|||
testAuth.afterAll(async ({ browser }) => { | |||
test.slow() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow extra time for the project and file handle to be cleaned up
await userPage.goto(getDefaultDiscussionPath(userProject.id)) | ||
await goToDashboardPage( | ||
userPage, | ||
getDefaultDiscussionPath(userProject.id), | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Playwright's goto
method waits for the 'load' event, which may be fired before SWC is ready for interaction. Instead, use custom goTo***
methods that wait for SWC to fully load, e.g. SynapseNavDrawer is loaded for authenticated users.
@@ -257,8 +236,12 @@ test.describe('Discussions', () => { | |||
// retry if the view count hasn't updated | |||
await expect(async () => { | |||
// reload is necessary for view count to update | |||
await userPage.reload() | |||
await expectDiscussionPageLoaded(userPage, userProject.id) | |||
await reloadDashboardPage(userPage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the custom goTo***
methods, use a custom reload***
method that waits for SWC to fully load
.click({ timeout: testInfo.timeout * 3 }) | ||
.click({ timeout: defaultExpectTimeout * 3 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
testInfo.timeout
is the test timeout. The expect timeout is not currently available in the testInfo
fixture, but Playwright plans to expose the timeout in the future
test.fail( | ||
browserName === 'webkit', | ||
`Playwright is not preserving the File's lastModified time in webkit, so | ||
file upload fails because it seems like the file was modified during | ||
upload. See https://github.com/microsoft/playwright/issues/27452. Fix | ||
planned for Playwright v1.40.`, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in Playwright v1.40
{ scope: 'worker', timeout: 2 * 60 * 1000 }, | ||
{ scope: 'worker', timeout: defaultTestTimeout * 2 }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixtures intermittently timed out on linux runner -- allow time to create/setup two users
// Perform authentication steps | ||
await page.goto('/') | ||
await waitForInitialPageLoad(page) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This page reload is unnecessary -- the page has already navigated to the base URL when this method is called
await expect( | ||
userPage.getByRole('heading', { name: 'Your Projects' }), | ||
).toBeVisible() | ||
await testAuth.step('should delete project', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete the project via the UI
testAuth.afterAll(async ({ browser }) => { | ||
test.slow() | ||
// if test failed before project was deleted, then delete project here | ||
if (projectId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clean up the project, if the test failed before deleting the project via the UI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like the pattern of deleting using admin credentials only if the UI path failed
await testAuth.step('user should get teamId', async () => { | ||
await userPage.waitForURL(`/${teamHashBang}:**`) | ||
teamId = getTeamIdFromPathname(userPage.url()) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get the teamId before dismissing the alert and waiting for the team page to load, so that the team can be cleaned up in the afterAll if the test fails during these steps
const loadInvitedUser = userPage.getByText('Loading...') | ||
await expect(loadInvitedUser).toBeVisible() | ||
await expect(loadInvitedUser).not.toBeVisible() | ||
await expect(userPage.getByText('Loading...')).not.toBeVisible() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove flaky wait for "Loading..." to be visible
@@ -203,6 +218,8 @@ test.describe('Teams', () => { | |||
) | |||
|
|||
testAuth.afterAll(async ({ userPage, validatedUserPage }) => { | |||
test.slow() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow extra time to clean up objects associated with the teams test
name: 'Trash Can', | ||
}) | ||
await expect(trashCanHeading).toBeVisible() | ||
// reload page if trash can deferred js does not load |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Safe to assume this probably intermittently fails because of resource constraints in CI, and not because of some other bug right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I think so -- I saw this behavior (and similar timeouts waiting for network responses) on the linux runners, but haven't seen it on the macOS runners
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
await successfulLoginResponsePromise | ||
await expect(async () => { | ||
expect(page.url()).not.toContain('LoginPlace') | ||
}).toPass() | ||
|
||
// Wait until the page reaches a state where all cookies are set | ||
await expect(page.getByLabel('Search')).toBeVisible() | ||
await expect(page.getByLabel('Projects')).toBeVisible() | ||
await expect(page.getByLabel('Your Account')).toBeVisible({ | ||
timeout: 30 * 1000, | ||
}) | ||
await authenticatedUserBundleResponsePromise | ||
await expectAuthenticatedNavDrawerLoaded(page) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting pattern to get the promises first and hold off on the await
until you need them, but it makes sense since they aren't necessarily sequential--I like it.
testAuth.afterAll(async ({ browser }) => { | ||
test.slow() | ||
// if test failed before project was deleted, then delete project here | ||
if (projectId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like the pattern of deleting using admin credentials only if the UI path failed
// FIXME: expect timeout not available in testInfo fixture in v1.39 | ||
// change tests to use testInfo fixture once expect settings are exposed, | ||
// see: https://github.com/microsoft/playwright/issues/27915 | ||
export const defaultExpectTimeout = process.env.CI ? 60 * 1000 : 5 * 1000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, huge difference in CI to get this to be reliable.
release-**
branches in the Sage repo and only run one shard at a time