Skip to content
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

Merged
merged 12 commits into from
Nov 28, 2023
Merged

SWC-6605 #5235

merged 12 commits into from
Nov 28, 2023

Conversation

hallieswan
Copy link
Contributor

@hallieswan hallieswan commented Nov 27, 2023

  • Use a macOS runner for e2e tests to reduce network flakiness, but only run workflow on release-** branches in the Sage repo and only run one shard at a time
  • Fix common failure points in e2e tests, e.g. adding functions for reloading page that wait for SWC to be ready for interaction and deleting project via UI if possible, otherwise deleting via API
  • bump Playwright version

# 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 }}
Copy link
Contributor Author

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'
Copy link
Contributor Author

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 }}
Copy link
Contributor Author

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

Comment on lines +85 to +86
# But skip this job if the previous job was cancelled or skipped
if: ${{ !cancelled() && needs.playwright-tests.result != 'skipped' }}
Copy link
Contributor Author

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 (
Copy link
Contributor Author

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()
Copy link
Contributor Author

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

Comment on lines -176 to +154
await userPage.goto(getDefaultDiscussionPath(userProject.id))
await goToDashboardPage(
userPage,
getDefaultDiscussionPath(userProject.id),
)

Copy link
Contributor Author

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)
Copy link
Contributor Author

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

Comment on lines -271 to +282
.click({ timeout: testInfo.timeout * 3 })
.click({ timeout: defaultExpectTimeout * 3 })
Copy link
Contributor Author

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

Comment on lines -334 to -340
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.`,
)
Copy link
Contributor Author

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 },
Copy link
Contributor Author

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

Comment on lines -70 to -72
// Perform authentication steps
await page.goto('/')
await waitForInitialPageLoad(page)
Copy link
Contributor Author

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 () => {
Copy link
Contributor Author

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

Comment on lines +82 to +85
testAuth.afterAll(async ({ browser }) => {
test.slow()
// if test failed before project was deleted, then delete project here
if (projectId) {
Copy link
Contributor Author

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

Copy link
Contributor

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

Comment on lines +86 to +89
await testAuth.step('user should get teamId', async () => {
await userPage.waitForURL(`/${teamHashBang}:**`)
teamId = getTeamIdFromPathname(userPage.url())
})
Copy link
Contributor Author

@hallieswan hallieswan Nov 28, 2023

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

Comment on lines -103 to +109
const loadInvitedUser = userPage.getByText('Loading...')
await expect(loadInvitedUser).toBeVisible()
await expect(loadInvitedUser).not.toBeVisible()
await expect(userPage.getByText('Loading...')).not.toBeVisible()
Copy link
Contributor Author

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()
Copy link
Contributor Author

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

@hallieswan hallieswan marked this pull request as ready for review November 28, 2023 01:34
@hallieswan hallieswan requested a review from nickgros November 28, 2023 01:37
@hallieswan hallieswan self-assigned this Nov 28, 2023
name: 'Trash Can',
})
await expect(trashCanHeading).toBeVisible()
// reload page if trash can deferred js does not load
Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor

@nickgros nickgros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

Comment on lines +124 to +131
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)
Copy link
Contributor

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.

Comment on lines +82 to +85
testAuth.afterAll(async ({ browser }) => {
test.slow()
// if test failed before project was deleted, then delete project here
if (projectId) {
Copy link
Contributor

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
Copy link
Contributor

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.

@hallieswan hallieswan merged commit 880b7f2 into Sage-Bionetworks:develop Nov 28, 2023
@hallieswan hallieswan deleted the SWC-6605 branch November 28, 2023 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants