From 8030b6d1407869cf90e2869ab24b6743450236b2 Mon Sep 17 00:00:00 2001 From: Olivier Gorzalka Date: Fri, 25 Sep 2026 16:02:29 +0200 Subject: [PATCH 1/3] test: check that __() sends text domains to WordPress in the browser tests WordPress's __() is renamed __wp() by the framework's patch, and pollora/helper-overrider's __() routes a call with a text domain to WordPress and a call with replacements to Laravel. If Laravel reclaims the name, nothing fails: WordPress catalogues just stop resolving. The e2e-features plugin ships a fr_FR catalogue and a REST route that loads it and answers what __() and __wp() return. Replayed on a site: with the WordPress side of the resolver disabled, the string comes back untranslated and the test fails. --- .../app/Endpoints/Translations.php | 34 ++++++++++++++++++ .../languages/e2e-features-fr_FR.mo | Bin 0 -> 453 bytes .../languages/e2e-features-fr_FR.po | 13 +++++++ tests/e2e/specs/features.spec.ts | 15 ++++++++ 4 files changed, 62 insertions(+) create mode 100644 tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php create mode 100644 tests/e2e/fixtures/plugins/e2e-features/languages/e2e-features-fr_FR.mo create mode 100644 tests/e2e/fixtures/plugins/e2e-features/languages/e2e-features-fr_FR.po diff --git a/tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php b/tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php new file mode 100644 index 00000000..6d6aacfb --- /dev/null +++ b/tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php @@ -0,0 +1,34 @@ + $domain === 'e2e-features' ? 'fr_FR' : $locale, 10, 2); + unload_textdomain('e2e-features'); + load_plugin_textdomain('e2e-features', false, 'e2e-features/languages'); + + return [ + 'wordpress' => __('E2E greeting', 'e2e-features'), + 'untranslated' => __('E2E string outside the catalogue', 'e2e-features'), + 'laravel' => __('Shipping :brand', ['brand' => 'Example']), + 'wpNative' => __wp('E2E greeting', 'e2e-features'), + ]; + } +} diff --git a/tests/e2e/fixtures/plugins/e2e-features/languages/e2e-features-fr_FR.mo b/tests/e2e/fixtures/plugins/e2e-features/languages/e2e-features-fr_FR.mo new file mode 100644 index 0000000000000000000000000000000000000000..60a64038bda141568deb980951dd0afa44bd38a8 GIT binary patch literal 453 zcmah_!AiqG5RKv~c=D=;IVw7u2CH>zJhV-q(qbu5JSl53jVbAF*xiVJh#%ok`7KUb z#G?a`_ulemnAz{WollQzn{mK6X${x)hSt2xI$}I+dEPDaKI4nE7l$zvhRBtw@McCY zDRVf^@qvsjwGz+<5|XYlWc@kS+BlrrqRes76c$r0z@JF#Ff~%yN;+-UFREx{L70+U zv7e5o@!!nOY2XjFa-_KJqb324-rZSU$x`(pdzHqLi|*3|dw;oh{DKU|D$_Y{E1>sM zI)8ST;?VGdye*ET<6&VCUSM#AVK?n`MfXyi2ggAuf`G#~r?;}b?BDD}ZcY%eFwe={ zpH+>K6(-uOtN>N7t&PGyY-Dt(;08KJeg6?hdc~&*ppbC!`+43#tEFxX 1);\n" +"X-Domain: e2e-features\n" + +msgid "E2E greeting" +msgstr "Bonjour depuis le catalogue" diff --git a/tests/e2e/specs/features.spec.ts b/tests/e2e/specs/features.spec.ts index d16eed5c..da4cd76c 100644 --- a/tests/e2e/specs/features.spec.ts +++ b/tests/e2e/specs/features.spec.ts @@ -163,6 +163,21 @@ test.describe('Assets', () => { }); }); +test.describe('Translations through __()', () => { + test("a text domain goes to WordPress's catalogues, replacements to Laravel", async () => { + const context = await visitor(); + const translations = await (await context.get(homeUrl('/wp-json/e2e/v1/translations'))).json(); + await context.dispose(); + + expect(translations).toEqual({ + wordpress: 'Bonjour depuis le catalogue', + untranslated: 'E2E string outside the catalogue', + laravel: 'Shipping Example', + wpNative: 'Bonjour depuis le catalogue', + }); + }); +}); + test.describe('The active theme', () => { test('registers the menu locations its config/menus.php declares', async ({ requestUtils }) => { const configFile = join(siteDir, 'themes', activeTheme(), 'config', 'menus.php'); From 83715ef27dcf0bb3e425de530709a098c7b5307a Mon Sep 17 00:00:00 2001 From: Olivier Gorzalka Date: Fri, 25 Sep 2026 16:02:30 +0200 Subject: [PATCH 2/3] ci: run the browser tests in Firefox and WebKit every night E2E_BROWSERS selects the Playwright projects (chromium by default). Pull requests and pushes keep Chromium alone; the nightly schedule and a manual run use all three engines. Measured locally in Firefox: the suite passes but for the the_content check, which fails on pollora-test for a theme defect already fixed in theme-apiary. --- .github/workflows/ci.yml | 12 +++++++++++- tests/e2e/playwright.config.ts | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34a802c6..66d1add4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,11 @@ on: branches: [main, develop, 'feature/**', 'hotfix/**', 'release/**'] pull_request: branches: [main, develop] + # Nightly, on the default branch: the browser tests in Firefox and WebKit as well as + # Chromium, which pull requests run alone to stay fast. + schedule: + - cron: '30 3 * * *' + workflow_dispatch: jobs: tests: @@ -238,6 +243,11 @@ jobs: # authoritative: a deployment dumped with --classmap-authoritative answers # from the classmap alone. Theme and plugin classes are autoloaded at # runtime, and every front-end page once answered 404 there (#320). + # Chromium on pushes and pull requests; all three engines on the nightly and on a + # manual run. + env: + E2E_BROWSERS: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && 'chromium,firefox,webkit' || 'chromium' }} + strategy: fail-fast: false matrix: @@ -328,7 +338,7 @@ jobs: working-directory: packages/framework/tests/e2e run: | npm ci - npx playwright install --with-deps chromium + npx playwright install --with-deps ${E2E_BROWSERS//,/ } # DDEV serves HTTPS with a mkcert certificate when mkcert is present. # Say which case the runner is in rather than guessing. diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts index 9ee9ee1f..f0b3451e 100644 --- a/tests/e2e/playwright.config.ts +++ b/tests/e2e/playwright.config.ts @@ -9,6 +9,7 @@ import { defineConfig, devices } from '@playwright/test'; * WP_BASE_URL WordPress itself (`siteurl`), e.g. https://pollora-test.ddev.site/cms/ — * read by @wordpress/e2e-test-utils-playwright for wp-admin, login and REST * E2E_WP_CLI how to run WP-CLI against that site, e.g. "ddev wp" (default) + * E2E_BROWSERS comma-separated: chromium (default), firefox, webkit — the nightly runs all three */ const homeUrl = process.env.E2E_HOME_URL ?? 'https://pollora-test.ddev.site'; // Trailing slash: relative paths such as wp-login.php must resolve inside /cms. @@ -29,6 +30,20 @@ if (! process.env.NODE_EXTRA_CA_CERTS) { } } +const browsers: Record = { + chromium: 'Desktop Chrome', + firefox: 'Desktop Firefox', + webkit: 'Desktop Safari', +}; + +const projects = (process.env.E2E_BROWSERS ?? 'chromium').split(',').map((name) => name.trim()).map((name) => { + if (! (name in browsers)) { + throw new Error(`E2E_BROWSERS: unknown browser "${name}" (known: ${Object.keys(browsers).join(', ')})`); + } + + return { name, use: { ...devices[browsers[name]] } }; +}); + export default defineConfig({ testDir: './specs', globalSetup: './global-setup.ts', @@ -46,5 +61,5 @@ export default defineConfig({ screenshot: 'only-on-failure', video: 'retain-on-failure', }, - projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], + projects, }); From 1ea8e96c0d5abb488a8c8d59bda4f63d92f1bb79 Mon Sep 17 00:00:00 2001 From: Olivier Gorzalka Date: Fri, 25 Sep 2026 16:18:54 +0200 Subject: [PATCH 3/3] test: load the fr_FR catalogue as the current locale's Since WordPress 6.5 translations are kept per locale. The route loaded the plugin's catalogue as fr_FR through plugin_locale, which only worked on a site whose language is fr_FR (pollora-test); on the CI site, in en_US, __() found nothing. Measured with the locale forced to en_US: the former loading leaves the string untranslated, this one translates it. --- .../e2e-features/app/Endpoints/Translations.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php b/tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php index 6d6aacfb..67ff1f04 100644 --- a/tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php +++ b/tests/e2e/fixtures/plugins/e2e-features/app/Endpoints/Translations.php @@ -10,8 +10,8 @@ /** * What `__()` answers, on each side of the helper that shares the name: WordPress keeps * its own as `__wp()`, and `__()` sends a call with a text domain to WordPress and a call - * with replacements to Laravel. This plugin's catalogue is loaded in fr_FR whatever the - * site's language. + * with replacements to Laravel. This plugin's fr_FR catalogue is what WordPress finds, + * whatever the site's language. */ #[WpRestRoute('e2e/v1', '/translations')] class Translations @@ -20,9 +20,11 @@ class Translations #[Method('GET')] public function show(): array { - add_filter('plugin_locale', static fn (string $locale, string $domain): string => $domain === 'e2e-features' ? 'fr_FR' : $locale, 10, 2); + // Loaded as the catalogue of the current locale, whatever the site's language: + // since WordPress 6.5 translations are kept per locale, so loading it as fr_FR + // on an en_US site would leave __() nothing to find. unload_textdomain('e2e-features'); - load_plugin_textdomain('e2e-features', false, 'e2e-features/languages'); + load_textdomain('e2e-features', WP_PLUGIN_DIR.'/e2e-features/languages/e2e-features-fr_FR.mo', determine_locale()); return [ 'wordpress' => __('E2E greeting', 'e2e-features'),