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

Playwright e2e tests are configured to start wp-env but don't wait for REST API to be advertised #61627

Closed
GraemeF opened this issue May 13, 2024 · 8 comments · Fixed by #62331
Assignees
Labels
[Package] Scripts /packages/scripts [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended

Comments

@GraemeF
Copy link

GraemeF commented May 13, 2024

Description

Playwright is configured to start wp-env if not already running, but when it does the REST API likely isn't ready in time for the globalSetup function to use it. To get around that, the GitHub workflow starts wp-env ahead of the tests in the hope that it's started by the time the globalSetup function tries to use it.

Step-by-step reproduction instructions

In the gutenberg repo, make sure wp-env is not already running, then run the e2e tests:

npm run test:e2e

Expected behaviour

Playwright should wait for all required services to be available before running tests, or should not be configured to start wp-env at all, to clarify that this needs to be done ahead of time.

Actual behaviour

Playwright starts wp-env, waits for the WordPress port to be open, and then attempts to discover the location of the REST API. The REST API isn't immediately advertised via the link header, so discovery fails and the tests are not run.

> gutenberg@18.3.0 test:e2e
> wp-scripts test-playwright --config test/e2e/playwright.config.ts

Error: Failed to discover REST API endpoint.
 Link header: undefined

   at ../../../packages/e2e-test-utils-playwright/src/request-utils/rest.ts:32

  30 |
  31 | 	if ( ! restLink ) {
> 32 | 		throw new Error( `Failed to discover REST API endpoint.
     | 		      ^
  33 |  Link header: ${ links }` );
  34 | 	}
  35 |

    at getAPIRootURL (.../packages/e2e-test-utils-playwright/src/request-utils/rest.ts:32:9)
    at RequestUtils.setupRest (.../packages/e2e-test-utils-playwright/src/request-utils/rest.ts:42:29)
    at globalSetup (.../test/e2e/config/global-setup.ts:26:2)
@Mamaduka Mamaduka added [Type] Bug An existing feature does not function as intended [Package] Scripts /packages/scripts labels May 13, 2024
@Mamaduka
Copy link
Member

cc @WunderBart @swissspidy

Side note: I think the test runner shouldn't assume that the consumer will be using wp-env, at least when WP_BASE_URL is provided.

@GraemeF
Copy link
Author

GraemeF commented May 13, 2024

cc @WunderBart @swissspidy

Side note: I think the test runner shouldn't assume that the consumer will be using wp-env, at least when WP_BASE_URL is provided.

I think current behaviour would be to start wp-env regardless of WP_BASE_URL.

Edit: that's wrong - sorry 😄

@swissspidy
Copy link
Member

swissspidy commented May 13, 2024

cc @WunderBart @swissspidy

Side note: I think the test runner shouldn't assume that the consumer will be using wp-env, at least when WP_BASE_URL is provided.

Are you referring to this line?

command: 'npm run wp-env start',

I think current behaviour would be to start wp-env regardless of WP_BASE_URL.

Right now, with the webServer config Playwright first checks if there's already a server running (under WP_BASE_URL or http://localhost:8889) and responding with a reasonable status code. If not, it starts the server itself and waits up to 120 seconds.

Playwright should wait for all required services to be available before running tests [...]

Hmm maybe we could use webServer.url for that and point it to the REST API.

Something like that:

const baseUrl = process.env.WP_BASE_URL || 'http://localhost:8889';

// ...
webServer: {
		url: `${baseUrl}/?rest_route=/wp/v2`
		command: 'npm run wp-env start',
		port: 8889,
		timeout: 120_000, // 120 seconds.
		reuseExistingServer: true,
	},

[...] , or should not be configured to start wp-env at all, to clarify that this needs to be done ahead of time.

That doesn't sound like great DX to me.

@Mamaduka
Copy link
Member

@swissspidy,
You'll get an error when running e2e for custom WP_BASE_URL. Currently, I have to start the Docker. The test runner will start the environment, and then I can test my custom installations.

Previously, using the Docker or wp-env wasn't a requirement for the e2e test, but it seems it is.

@GraemeF, sorry, I went off-topic. I agree it makes sense to wait for REST API.

Screenshot

CleanShot 2024-05-13 at 19 59 40

@GraemeF
Copy link
Author

GraemeF commented May 13, 2024

We were trying to run some e2e tests on our own blocks in a similar way to gutenberg and noticed this. To fix we:

  • In the webServer config, remove port and instead use url so Playwright waits for a successful HTTP response before continuing, rather than just the port accepting connections
  • In globalSetup, add a retry around the call to requestUtils.setupRest so that the initial responses without the Link header don't make the setup fail

I'm not sure how WP_BASE_URL affects things but would be happy to submit a PR similar to the above.

@swissspidy
Copy link
Member

You'll get an error when running e2e for custom WP_BASE_URL. Currently, I have to start the Docker. The test runner will start the environment, and then I can test my custom installations.

I think config.webServer.url will solve this. It's currently not defined.

In the webServer config, remove port and instead use url so Playwright waits for a successful HTTP response before continuing, rather than just the port accepting connections

FWIW port is not actually a valid config option there 🤔 Maybe it got removed at some point or so. That might explain why it's not working. I think config.webServer.url should do the trick, and I don't like doing retries in globalSetup.

@GraemeF
Copy link
Author

GraemeF commented May 13, 2024

FWIW port is not actually a valid config option there 🤔 Maybe it got removed at some point or so. That might explain why it's not working.

You're right - port seems to have been removed! Hadn't spotted that.

I think config.webServer.url should do the trick, and I don't like doing retries in globalSetup.

Unfortunately not - we found that WordPress will initially respond without the Link header, and there is no retry mechanism for globalSetup. If this setup were migrated to a project then Playwright could be configured to retry.

@WunderBart
Copy link
Member

👋 I've added a simple retry mechanism for the API discovery using expect.poll in #62331. Looks like it's working as expected! 🤞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Scripts /packages/scripts [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended
4 participants