Skip to content

Fix wait / sleep which is causing many PRs to fail performance tests in CI for reasons unrelated to the PR#77726

Open
danluu wants to merge 3 commits intoWordPress:trunkfrom
danluu:try/perf-test-speedup-5
Open

Fix wait / sleep which is causing many PRs to fail performance tests in CI for reasons unrelated to the PR#77726
danluu wants to merge 3 commits intoWordPress:trunkfrom
danluu:try/perf-test-speedup-5

Conversation

@danluu
Copy link
Copy Markdown
Contributor

@danluu danluu commented Apr 28, 2026

This PR was originally created to stop every PR from having a failing CI run due to performance tests timing out at 60 minutes, which was blocking every PR for the #77716 fuzzing project. There was as race with #77725 and that issue solved the problem. However, the approach is different and this PR eliminates the 3s wait that #77725 has in successful cases. This seems to speed up the entire Performance CI run by approximately 2.5 minutes (no doubt there's a lot of noise and the true speedup might be 2 minutes or 3 minutes and not 2.5 minutes).

I originally closed this as a dup, but on seeing that this version has some advantages over the other one, I'm gong to re-open it.

BEGIN AI GENERATED TEXT

The performance job is not timing out because the Site Editor test suite or the
Site Editor itself became 20+ minutes slower. It is timing out because the
visitSiteEditor() Playwright helper can wait a full 60 seconds for a canvas
loader that has already appeared and disappeared.

The direct trigger was #77443. That PR did not change Site Editor loading code,
the performance spec, or the visitSiteEditor() helper. It changed runtime
timing enough to expose an existing race in the helper.

The latent helper bug came from the sequence of earlier helper changes, most
importantly #68667. #68667 made a missed loader a successful fallback path, but
only after spending the full 60 second timeout waiting for the loader to become
visible.

Once #77443 was on trunk, PR performance jobs compared two branches that both
contained the timing trigger. The Site Editor loading test calls
visitSiteEditor() 11 times per branch, so one artificial 60 second wait per
iteration adds about 22 minutes to a full PR performance run.

Relevant PRs and commits

What the helper does

On trunk before the fix, visitSiteEditor() contains this sequence:

await this.visitAdminPage( 'site-editor.php', query.toString() );

if ( ! options.showWelcomeGuide ) {
	await this.editor.setPreferences( 'core/edit-site', {
		welcomeGuide: false,
		welcomeGuideStyles: false,
		welcomeGuidePage: false,
		welcomeGuideTemplate: false,
	} );
}

if ( ! query.size || postId || canvas === 'edit' ) {
	const canvasLoader = this.page.locator(
		'.edit-site-canvas-loader, .edit-site-canvas-spinner'
	);

	try {
		await canvasLoader.waitFor( { state: 'visible', timeout: 60_000 } );
		await canvasLoader.waitFor( {
			state: 'hidden',
			timeout: 60_000,
		} );
	} catch {
		await this.page
			.getByRole( 'region', { name: 'Editor content' } )
			.waitFor();
	}
}

The catch block comment says "If the canvas loader is already disappeared, skip
the waiting", but the implementation cannot know that until after
canvasLoader.waitFor( { state: 'visible', timeout: 60_000 } ) has already
timed out.

The Site Editor performance loading test hits this path 11 times per branch:

const samples = 10;
const throwaway = 1;
const iterations = samples + throwaway;

await admin.visitSiteEditor( {
	postId: draftId,
	postType: 'page',
	canvas: 'edit',
} );

The test then records results.firstBlock from
metrics.getLoadingDurations().timeSinceResponseEnd, which is
performance.now() - responseEnd. That means the helper's 60 second wait is
included in the firstBlock metric even if the first block was already present.

Evidence from CI

The #77443 performance run compared the PR merge commit
cf45676490ae3900632a512f6deaa9ab259e2d54 against trunk and still finished,
but it was close to the 60 minute workflow limit. Its Site Editor summary showed
a signature 60 second firstBlock value on the PR side while server-side work
was normal:

site-editor firstBlock:
  cf45676490ae3900632a512f6deaa9ab259e2d54: 65353.75 ms
  trunk:                                    4077.75 ms
  change:                                  1502.69%

site-editor wpTotal:
  cf45676490ae3900632a512f6deaa9ab259e2d54: 420.25 ms
  trunk:                                    418.41 ms

site-editor wpDbQueries:
  cf45676490ae3900632a512f6deaa9ab259e2d54: 52
  trunk:                                    52

That rules out a PHP/server/DB slowdown as the main cause of the 60 second
number.

After #77443 landed, later PRs compared PR branches against trunk where both
sides had the timing trigger. For example, the #77675 performance run was
canceled at the 60 minute job timeout while running the second Site Editor
branch:

23:52:49 site-editor PR branch starts running tests
00:08:06 site-editor PR branch finishes running tests
00:08:26 site-editor trunk branch starts running tests
00:18:17 job canceled at the 60 minute workflow timeout

That is consistent with roughly 11 minutes of artificial loader-wait delay per
branch, plus normal setup/build/test time.

Local reproduction and double-check

I reproduced the behavior with the actual performance test path, not a reduced
direct page.goto() probe. With instrumentation added around the old
visitSiteEditor() helper on #77443's PR merge commit, the page was already
loaded before the 60 second wait started:

after_visit_admin_page:
  wallMs=1804
  sinceResponseEnd=1530
  loaderPresent=false
  editorRegion=true
  iframePresent=true
  iframeBlocks=1437

after_set_preferences:
  wallMs=1884
  sinceResponseEnd=1662
  loaderPresent=false
  editorRegion=true
  iframeBlocks=1437

before_loader_visible_wait:
  wallMs=1894
  sinceResponseEnd=1685
  loaderPresent=false
  editorRegion=true
  iframeBlocks=1437

loader_wait_catch:
  wallMs=61934
  sinceResponseEnd=61723
  waitError="TimeoutError: locator.waitFor: Timeout 60000ms exceeded."
  iframeBlocks=1437

reported firstBlock=61807ms

This answers the important question directly: yes, the content was present
before 60 seconds. The iframe already contained 1437 blocks before the helper
started the 60 second loader-visible wait.

I then ran the same instrumented path on the pre-#77443 base commit
90e45267257fc4a4da0095933ecc24fa3bae776d. There the loader was still present
when the helper started waiting, so the 60 second timeout was not hit:

after_visit_admin_page:
  wallMs=739
  sinceResponseEnd=513
  loaderPresent=true
  editorRegion=false
  iframePresent=false

before_loader_visible_wait:
  wallMs=755
  sinceResponseEnd=531
  loaderPresent=true

after_loader_visible_wait:
  wallMs=841

after_loader_hidden_wait:
  wallMs=1020

reported firstBlock=1306.7ms

This isolates the behavior change to #77443's merge comparison: the helper code
was the same, but the loader was missed after #77443 and not missed before it.

Why #77443 is the trigger but not the actual slowdown

The #77443 diff changes the Experiments screen and related settings plumbing:

lib/experimental/experiments/load.php
lib/experiments-page.php
lib/init.php
lib/load.php
package-lock.json
package.json
packages/e2e-test-utils-playwright/src/request-utils/gutenberg-experiments.ts
routes/experiments-home/api.ts
routes/experiments-home/package.json
routes/experiments-home/route.ts
routes/experiments-home/stage.tsx
routes/experiments-home/style.scss

It does not change these Site Editor or performance-test files:

packages/edit-site
packages/e2e-test-utils-playwright/src/admin/visit-site-editor.ts
test/performance/specs/site-editor.spec.js
packages/scripts/config/playwright.config.js
test/performance/playwright.config.ts

So the correct interpretation is:

  1. Fix flaky navigation-frontend-interactivity e2e tests #68667 left a race in visitSiteEditor(): a missed loader costs 60 seconds
    and then still succeeds.
  2. Experiments: Rebuild the wp-admin Experiments screen on the wp-build routes pattern #77443 changed page/runtime timing enough that, in performance CI, the
    loader was already gone by the time visitSiteEditor() started waiting for
    it to become visible.
  3. The performance harness records the helper delay as firstBlock.
  4. Once Experiments: Rebuild the wp-admin Experiments screen on the wp-build routes pattern #77443 was on trunk, both compared branches hit the same delay, pushing
    the job past the workflow's 60 minute timeout.

Fix direction

The helper should not require the loader to appear. It should wait for either:

  • the loader to be present, or
  • a ready editor/canvas state that proves the loader has already come and gone.

Then it should verify the loader is absent and the editor content/canvas is
ready. That preserves the intent of #61629 and #61816, while avoiding the
60-second penalty introduced by the fallback behavior from #68667.

END AI GENERATED TEXT

Note that this PR was AI generated (GPT-5.5)

@github-actions github-actions Bot added [Package] E2E Tests /packages/e2e-tests First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository labels Apr 28, 2026
@github-actions
Copy link
Copy Markdown

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @danluu! In case you missed it, we'd love to have you join us in our Slack community.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@danluu danluu changed the title Avoid missed site editor canvas loader wait Fix wait / sleep which is causing many PRs to fail performance tests in CI for reasons unrelated to the PR Apr 28, 2026
@danluu danluu closed this Apr 28, 2026
@danluu danluu reopened this Apr 28, 2026
@danluu danluu force-pushed the try/perf-test-speedup-5 branch from 0cf755b to e51d754 Compare April 28, 2026 01:42
@danluu danluu marked this pull request as ready for review April 28, 2026 01:43
@danluu danluu requested a review from kevin940726 as a code owner April 28, 2026 01:43
@github-actions
Copy link
Copy Markdown

Warning: Type of PR label mismatch

To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.

  • Required label: Any label starting with [Type].
  • Labels found: First-time Contributor, [Package] E2E Tests.

Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: danluu <danluu@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@danluu danluu force-pushed the try/perf-test-speedup-5 branch from e51d754 to 72498c6 Compare April 28, 2026 02:26
Copy link
Copy Markdown
Member

@dmsnell dmsnell left a comment

Choose a reason for hiding this comment

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

these two tests both define isVisibleElement and isReadyElement and they look identical. let’s extract them? I think that will make the diff look much smaller, especially if we define these helpers somewhere in the module global scope so that they aren’t right there in the waitForFunction lines.

@danluu danluu mentioned this pull request Apr 28, 2026
Comment thread packages/e2e-test-utils-playwright/src/admin/visit-site-editor.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] E2E Tests /packages/e2e-tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants