Problem/Motivation
In #3467492: [policy, no patch] Replace Nightwatch with Playwright we decided to switch from Nightwatch to Playwright for most of the tests that Nightwatch currently does. And for some tests to switch to Axe in phpunit, which has already had an issue open for some time at #3338664: Migrate Nightwatch Axe tests to PHPUnit
Opening this plan issue to co-ordinate the actual migration.
Steps to reproduce
Proposed resolution
Remaining tasks
1. A core pipeline that will run playwright tests + at least one test converted from nightwatch to playwright so it has something to run.
2. Issues to convert the other tests, including to phpunit where appropriate per #3338664: Migrate Nightwatch Axe tests to PHPUnit
3. An issue to remove the core nightwatch pipeline when there are no tests left.
4. An issue to remove the nightwatch dependency (probably in Drupal 12?)
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|
Issue fork drupal-3553673
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
nicrodgersComment #6
longwaveTrial run, the login test passes inside ddev:
This MR was heavily assisted by Claude Code.
Comment #7
longwaveAmazing!
Comment #8
longwaveAll non-a11y tests converted, 73 passes locally. The test suite takes just under 14 minutes on my machine, hopefully we can parallelise it in some way.
Comment #9
longwaveCI is timing out on every test.
Comment #10
tom kondaWhy don't use ES Modules for new test scripts?
According to npm-esm-vs-cjs data, over 10% of NPM packages already adopted ES Module only package in Dec 2026.
Furthermore, no supporting ES Modules packages decrease year by year and it's pace are increased.
I think adopting ES Modules for new test scripts is better than CommonJS.
Comment #11
longwave@tom konda Good idea, thanks - converted in a recent commit.
Comment #12
tom konda@longwave
Good works, thanks.
Comment #13
longwaveThinking about this again: while we agreed to swap Nightwatch for Playwright, there don't seem to be many people interested in Playwright tests. If we can use AI for this, should we just use AI to convert the Nightwatch tests to PHPUnit FunctionalJavascript tests instead? Would that make them easier to maintain?
Comment #14
mstrelan commentedThat was my original proposal in the policy issue. The people who write NW/PW tests don't seem to be the same people who are maintaining them.
Comment #15
catchWe already have #3338664: Migrate Nightwatch Axe tests to PHPUnit open for axe + functional js, should we do that first and see what's left?
Comment #16
murzTested the Playwright migration, and it works pretty well, thank you!
To speed up, I think we can start with small steps, the first one is just to provide the Playwright's
drupal-fixtures.mjsand the working pipeline, having this in Core - users will be able to start writing their own Playwright tests already, instead of Nightwatch.For me, everything in the MR looks great, so seems we have to resolve only the "CI is timing out on every test" issue, right?
And in addition to introducing
core/tests/Drupal/Playwright/drupal-fixtures.mjs- would be great to provide a contrib helper module that provides these functions as a dev dependency.This will allow switching from Nightwatch to Playwright tests for contrib module developers without waiting for the Drupal 11.3 end-of-life.
Because with the current approach, if users still want to keep test coverage for Drupal below 11.4, they should support both - Nightwatch for Drupal <11.4 and Playwright for Drupal 11.4+.
I think a good candidate for this can be https://www.drupal.org/project/playwright - just put there the
drupal-fixtures.mjsand other fixtures, and developers will be able to install thedrupal/playwrightmodule as dev dependency to start using it even for old Drupal versions. What do you think about this?Comment #17
murzFound the source of this issue! The root issue is that Drupal is intentionally installed into the subdirectory
http://localhost/subdirectoryto check that everything works with subdir installation mode.Here is a pipeline that passes at least three tests: https://git.drupalcode.org/issue/drupal-3553673/-/jobs/8940595
And to make Playwright navigate by relative URLs, keeping the subdirectory, we should do two things:
1. Create the browser context with
/symbol at the end of the directory.I tested this via a quick fix in the
drupal-fixtures.mjs:2. Use
page.goto()with relative urls everywhere:Also, using no leading slash like this
await page.goto('user/login')should work too.Maybe we can invent a way to simplify this somehow, to not ask to add a dot on every
page.goto()call, but for now - have no idea how to do this.But we should somehow resolve the
./URLs issue to make it impossible to make mistakes by passing non-relative URLs, because this will produce tricky errors like we have now - the tests work well on the localhost, but fails on the pipeline, because the pipeline runs the tests with the subdirectory, but localhost - not.Any ideas on how to resolve these two issues?
Comment #18
murzAlso, found one more repo that tries to provide Playwright fixtures for Drupal: https://gitlab.com/mog33/playwright-for-drupal-tests - but there the described issue is not resolved too, it just tests the root path without the subdirectory. And the same issue is with www.drupal.org/project/playwright
Comment #19
murzAlso, would be great to create a separate container image with pre-installed Playwright and browsers, to prevent re-installing a bunch of packages and downloading browsers on every run.
Downloading browsers can be resolved by caching, but installing system packages can be cached only as a separate container image, so I'd prefer to put the pre-downloaded browsers into that image too.
The image can be done over the current Drupal image: registry.gitlab.com/drupal-infrastructure/drupalci/drupalci-environments/php-8.1-apache:production
Here is a list of packages that should be added for Playwright to work well:
And here are the browsers that downloads on every CI run:
But this can be done later as a separate task.
Comment #20
murzFiled an issue on the Playwright to simplify: this https://github.com/microsoft/playwright/issues/39720 - upvote pls ;)
Comment #21
longwaveThere is still the question in #13 of whether we want to do this at all, because there don't seem to be many people interested in maintaining these tests.
Comment #22
murzMany contrib projects already use Playwright tests, you can see the usage here: https://search.tresbien.tech/search?q=%40playwright%2Ftest&num=50&ctx=0
At least, the Canvas project has used Playwright for a long time, instead of Nighwatch.
But all of them invent their own kludges to make it work with Drupal, instead of consolidating and reusing the same approach for all projects. So, I believe that Drupal Core should provide this "the best approach" out of the box, and modules will use it in their pipelines.
About converting all the Core tests from Nightwatch to Playwright, we can actually keep it as is with Nightwatch, just start to write new tests in Playwright.
The first and crucial step is to provide Drupal fixtures for Playwright, and a couple of test examples to use as a base for new tests in Core and contrib.
Comment #23
mstrelan commentedThe whole point of this is to remove nightwatch, because the tests we currently have are incredibly flakey and no one wants to maintain them.
Comment #24
murzThen, the easiest solution is just to remove Nightwatch tests, and live calmly without any functional tests? 😂
Wait, this is not a good solution, right? 😉
So, we have two options:
1. Keep the Nightwatch tests as is and live in the flaky world.
2. Migrate all tests to Playwright, with the hope that there will be more Playwright fans than Nightwatch fans, who will want to maintain them.
Let's choose the second option, and convert the current Nightwatch tests to Playwright, and make it work well, as the largest part of the job was already done by @longwave.
I updated all the tests to use relative paths in the
page.goto(), that should fix the pipeline. Until https://github.com/microsoft/playwright/issues/39720 is implemented, let's live with this approach then.Comment #25
murzAnd, 🥁 - it works! The Playwright pipeline job is green with all tests passed well:
73 passed (15.0m)Please review the changes and the approach, and then we can clean up all debug code, and prepare the final version to merge.
Comment #26
star-szrAs a maintainer of one of the contrib projects currently using Playwright (because yes, Nightwatch is flaky as heck, and my use case is not covered by FunctionalJavascript tests, I tried):
At this time I can't offer to help develop or maintain Playwright tests in core, but would certainly make use of a consolidated approach if/when it gets into core. Edit: For the record, my approach was mostly a copy+paste of the implementation in the Canvas project, but I'm sure it has drifted since then.
I will say, because of the ability to record tests in Playwright, there seems to be potential for folks from a wider set of skills to at least help in putting tests together. This is speculative, those folks may never materialize, but worth recognizing I think.
Comment #27
nicxvan commentedThis looks great! Can we modify the runner to run them 100 times to see if they are more stable than nightwatch?
Comment #28
murzGreenPeace wouldn't like the carbon footprint of this 😁 but let's try: here is the pipeline https://git.drupalcode.org/issue/drupal-3553673/-/jobs/8961401
Comment #29
murzSeems this works! I published an image, based on the
registry.gitlab.com/drupal-infrastructure/drupalci/drupalci-environments/php-8.3-apache:productionhere: https://gitlab.com/murz-drupal/drupal-playwright/container_registryAnd it works!!! Tested on my own project, here is the green pipeline: https://git.drupalcode.org/project/logger/-/jobs/8961204
To test this image, set the path to the image like this in the Playwright job:
Comment #30
nicxvan commentedRe 28 yes, I am very aware of the energy usage, but it's a one time check to validate it's less flaky which will save countless runs over time.
Comment #31
murz100 times is too much, even 10 times does not fit into 30 min limit of the job. But, 8 times went well: https://git.drupalcode.org/issue/drupal-3553673/-/jobs/8975910
Comment #32
kir lazur commentedSince the original issue closed - https://github.com/microsoft/playwright/issues/39720
As an option for relative urls we may consider to use base.extend and add wrapper for goto in order to normalize url and use relative path
something like this:
Let me know please if it makes sense to you
Comment #33
murz@kir lazur, yeah - thank you for sharing! Since https://github.com/microsoft/playwright/issues/39720 is closed, seems we have to invent something on our side.
Your approach with a proxy function looks good to me! Now, we have to decide where to put this function, to make it included by default in all tests.
Comment #34
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #35
catchCross referencing #2538970: Improve the speed of \Drupal\Core\Theme\ThemeAccessCheck. In that issue we discovered that there is an entire test module to provide controllers for nightwatch to visit to enable themes, for a single test, when admin/appearance could be used instead. If that tests stays in nightwatch and doesn't move to a functional js test, we should clean up the theme installation method.