Skip to content

Commit 94ecc97

Browse files
committed
Fix blog collection
1 parent fc49435 commit 94ecc97

12 files changed

Lines changed: 466 additions & 32 deletions

File tree

assets/css-flags/flags.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,21 @@
3333
'cy' => 'flag-icon-gb-wls',
3434
'da_DK' => 'flag-icon-dk',
3535
'de_AT' => 'flag-icon-at',
36-
'de_CH' => 'flag-icon-ch',
3736
'de_DE' => 'flag-icon-de',
3837
'de_DE_formal' => 'flag-icon-de',
38+
'de_CH' => 'flag-icon-ch',
3939
'de_CH_informal' => 'flag-icon-ch',
4040
'dzo' => 'flag-icon-bt',
4141
'el' => 'flag-icon-gr',
4242
'en_NZ' => 'flag-icon-nz',
43-
'en_CA' => 'flag-icon-ca',
4443
'en_GB' => 'flag-icon-gb',
45-
'en_AU' => 'flag-icon-au',
4644
'en_ZA' => 'flag-icon-za',
45+
'en_AU' => 'flag-icon-au',
46+
'en_CA' => 'flag-icon-ca',
4747
'eo' => 'flag-icon-eu',
48-
'es_ES' => 'flag-icon-es',
49-
'es_MX' => 'flag-icon-mx',
5048
'es_CO' => 'flag-icon-co',
51-
'es_CL' => 'flag-icon-cl',
49+
'es_ES' => 'flag-icon-es',
50+
'es_AR' => 'flag-icon-ar',
5251
'es_CR' => 'flag-icon-cr',
5352
'es_PE' => 'flag-icon-pe',
5453
'es_VE' => 'flag-icon-ve',
@@ -57,14 +56,15 @@
5756
'es_UY' => 'flag-icon-uy',
5857
'es_PR' => 'flag-icon-pr',
5958
'es_GT' => 'flag-icon-gt',
60-
'es_AR' => 'flag-icon-ar',
59+
'es_MX' => 'flag-icon-mx',
60+
'es_CL' => 'flag-icon-cl',
6161
'et' => 'flag-icon-ee',
6262
'eu' => 'flag-icon-es',
6363
'fa_IR' => 'flag-icon-ir',
6464
'fa_AF' => 'flag-icon-af',
6565
'fi' => 'flag-icon-fi',
66-
'fr_CA' => 'flag-icon-ca',
6766
'fr_FR' => 'flag-icon-fr',
67+
'fr_CA' => 'flag-icon-ca',
6868
'fr_BE' => 'flag-icon-be',
6969
'fur' => 'flag-icon-it',
7070
'gd' => 'flag-icon-gb-sct',
@@ -106,10 +106,10 @@
106106
'pa_IN' => 'flag-icon-in',
107107
'pl_PL' => 'flag-icon-pl',
108108
'ps' => 'flag-icon-af',
109-
'pt_PT_ao90' => 'flag-icon-90',
110109
'pt_PT' => 'flag-icon-pt',
111-
'pt_AO' => 'flag-icon-ao',
112110
'pt_BR' => 'flag-icon-br',
111+
'pt_AO' => 'flag-icon-ao',
112+
'pt_PT_ao90' => 'flag-icon-90',
113113
'ro_RO' => 'flag-icon-ro',
114114
'ru_RU' => 'flag-icon-ru',
115115
'sah' => 'flag-icon-ru',
@@ -135,8 +135,8 @@
135135
'uz_UZ' => 'flag-icon-uz',
136136
'vi' => 'flag-icon-vn',
137137
'zh_TW' => 'flag-icon-tw',
138-
'zh_HK' => 'flag-icon-hk',
139138
'zh_CN' => 'flag-icon-cn',
139+
'zh_HK' => 'flag-icon-hk',
140140
);
141141

142142
/**

assets/flags/flags.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,21 @@
3333
'cy' => 'wales.png',
3434
'da_DK' => 'dk.png',
3535
'de_AT' => 'at.png',
36-
'de_CH' => 'ch.png',
3736
'de_DE' => 'de.png',
3837
'de_DE_formal' => 'de.png',
38+
'de_CH' => 'ch.png',
3939
'de_CH_informal' => 'ch.png',
4040
'dzo' => 'bt.png',
4141
'el' => 'gr.png',
4242
'en_NZ' => 'nz.png',
43-
'en_CA' => 'ca.png',
4443
'en_GB' => 'gb.png',
45-
'en_AU' => 'au.png',
4644
'en_ZA' => 'za.png',
45+
'en_AU' => 'au.png',
46+
'en_CA' => 'ca.png',
4747
'eo' => 'europeanunion.png',
48-
'es_ES' => 'es.png',
49-
'es_MX' => 'mx.png',
5048
'es_CO' => 'co.png',
51-
'es_CL' => 'cl.png',
49+
'es_ES' => 'es.png',
50+
'es_AR' => 'ar.png',
5251
'es_CR' => 'cr.png',
5352
'es_PE' => 'pe.png',
5453
'es_VE' => 've.png',
@@ -57,14 +56,15 @@
5756
'es_UY' => 'uy.png',
5857
'es_PR' => 'pr.png',
5958
'es_GT' => 'gt.png',
60-
'es_AR' => 'ar.png',
59+
'es_MX' => 'mx.png',
60+
'es_CL' => 'cl.png',
6161
'et' => 'ee.png',
6262
'eu' => 'es.png',
6363
'fa_IR' => 'ir.png',
6464
'fa_AF' => 'af.png',
6565
'fi' => 'fi.png',
66-
'fr_CA' => 'ca.png',
6766
'fr_FR' => 'fr.png',
67+
'fr_CA' => 'ca.png',
6868
'fr_BE' => 'be.png',
6969
'fur' => 'it.png',
7070
'gd' => 'scotland.png',
@@ -106,10 +106,10 @@
106106
'pa_IN' => 'in.png',
107107
'pl_PL' => 'pl.png',
108108
'ps' => 'af.png',
109-
'pt_PT_ao90' => '90.png',
110109
'pt_PT' => 'pt.png',
111-
'pt_AO' => 'ao.png',
112110
'pt_BR' => 'br.png',
111+
'pt_AO' => 'ao.png',
112+
'pt_PT_ao90' => '90.png',
113113
'ro_RO' => 'ro.png',
114114
'ru_RU' => 'ru.png',
115115
'sah' => 'ru.png',
@@ -135,8 +135,8 @@
135135
'uz_UZ' => 'uz.png',
136136
'vi' => 'vn.png',
137137
'zh_TW' => 'tw.png',
138-
'zh_HK' => 'hk.png',
139138
'zh_CN' => 'cn.png',
139+
'zh_HK' => 'hk.png',
140140
);
141141

142142
/**

build/translations.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

includes/MslsBlog.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class MslsBlog {
2626
*
2727
* @var string
2828
*/
29-
private string $language;
29+
private string $language = '';
3030

3131
/**
3232
* Description e.g. "Deutsch", or "English", or "Italiano"

includes/MslsBlogCollection.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,9 @@ public static function get_configured_blog_description( int $blog_id, $descripti
133133
* @return object[]|\stdClass[]
134134
*/
135135
public function get_blogs_of_reference_user( MslsOptions $options ) {
136-
$reference_user = $options->has_value( 'reference_user' ) ?
137-
$options->reference_user :
138-
current( $this->get_users( 'ID', 1 ) );
139-
140-
if ( ! is_int( $reference_user ) ) {
141-
$reference_user = 0;
142-
}
136+
$reference_user = $options->has_value( 'reference_user' )
137+
? (int) $options->reference_user
138+
: (int) current( $this->get_users( 'ID', 1 ) );
143139

144140
return get_blogs_of_user( $reference_user );
145141
}

tests/phpunit/TestMslsBlogCollection.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,20 @@ final class TestMslsBlogCollection extends MslsUnitTestCase {
1111

1212
const TOTAL_USERS = 3210;
1313

14+
/**
15+
* Captures the last user-id argument passed to the mocked
16+
* `get_blogs_of_user()`. Reset in setUp(); read by individual tests that
17+
* verify the int cast in `MslsBlogCollection::get_blogs_of_reference_user()`.
18+
*
19+
* @var mixed
20+
*/
21+
protected $captured_user_id = null;
22+
1423
protected function setUp(): void {
1524
parent::setUp(); // TODO: Change the autogenerated stub
1625

26+
$this->captured_user_id = null;
27+
1728
Functions\when( 'count_users' )->justReturn( array( 'total_users' => self::TOTAL_USERS ) );
1829

1930
$options = \Mockery::mock( MslsOptions::class );
@@ -33,7 +44,12 @@ protected function setUp(): void {
3344

3445
Functions\expect( 'get_current_blog_id' )->atLeast()->once()->andReturn( 1 );
3546
Functions\expect( 'get_users' )->atLeast()->once()->andReturn( array() );
36-
Functions\expect( 'get_blogs_of_user' )->atLeast()->once()->andReturn( array( $a, $b, $c ) );
47+
Functions\expect( 'get_blogs_of_user' )->atLeast()->once()->andReturnUsing(
48+
function ( $user_id ) use ( $a, $b, $c ) {
49+
$this->captured_user_id = $user_id;
50+
return array( $a, $b, $c );
51+
}
52+
);
3753

3854
Functions\expect( 'get_blog_option' )->atLeast()->once()->andReturnUsing(
3955
function ( $blog_id, $option ) {
@@ -94,6 +110,31 @@ public function test_get_blogs_of_reference_user(): void {
94110
$this->assertIsArray( $obj->get_blogs_of_reference_user( $options ) );
95111
}
96112

113+
public function test_get_blogs_of_reference_user_casts_string_reference_user_to_int(): void {
114+
Functions\expect( 'get_site_option' )->once()->andReturn( array() );
115+
116+
$options = \Mockery::mock( MslsOptions::class );
117+
$options->reference_user = '5';
118+
$options->shouldReceive( 'has_value' )->with( 'reference_user' )->andReturn( true );
119+
120+
$obj = new MslsBlogCollection();
121+
$obj->get_blogs_of_reference_user( $options );
122+
123+
$this->assertSame( 5, $this->captured_user_id );
124+
}
125+
126+
public function test_get_blogs_of_reference_user_empty_fallback_is_safe(): void {
127+
Functions\expect( 'get_site_option' )->once()->andReturn( array() );
128+
129+
$options = \Mockery::mock( MslsOptions::class );
130+
$options->shouldReceive( 'has_value' )->with( 'reference_user' )->andReturn( false );
131+
132+
$obj = new MslsBlogCollection();
133+
$obj->get_blogs_of_reference_user( $options );
134+
135+
$this->assertSame( 0, $this->captured_user_id );
136+
}
137+
97138
public function test_get_current_blog_id(): void {
98139
Functions\expect( 'get_site_option' )->once()->andReturn( array() );
99140

tests/playwright/artifacts/html-report/index.html

Lines changed: 90 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
{
2+
"config": {
3+
"configFile": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/playwright.config.ts",
4+
"rootDir": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/specs",
5+
"forbidOnly": false,
6+
"fullyParallel": true,
7+
"globalSetup": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/setup/global-setup.ts",
8+
"globalTeardown": null,
9+
"globalTimeout": 0,
10+
"grep": {},
11+
"grepInvert": null,
12+
"maxFailures": 0,
13+
"metadata": {},
14+
"preserveOutput": "always",
15+
"projects": [
16+
{
17+
"outputDir": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/artifacts/test-results",
18+
"repeatEach": 1,
19+
"retries": 0,
20+
"metadata": {},
21+
"id": "local",
22+
"name": "local",
23+
"testDir": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/specs",
24+
"testIgnore": [
25+
"**/specs/live/**"
26+
],
27+
"testMatch": [
28+
"**/*.@(spec|test).?(c|m)[jt]s?(x)"
29+
],
30+
"timeout": 30000
31+
},
32+
{
33+
"outputDir": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/artifacts/test-results",
34+
"repeatEach": 1,
35+
"retries": 0,
36+
"metadata": {},
37+
"id": "live",
38+
"name": "live",
39+
"testDir": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/specs",
40+
"testIgnore": [],
41+
"testMatch": [
42+
"**/specs/live/**/*.spec.ts"
43+
],
44+
"timeout": 30000
45+
}
46+
],
47+
"quiet": false,
48+
"reporter": [
49+
[
50+
"list",
51+
null
52+
],
53+
[
54+
"json",
55+
{
56+
"outputFile": "./tests/playwright/artifacts/test-results.json"
57+
}
58+
],
59+
[
60+
"html",
61+
{
62+
"outputFolder": "./tests/playwright/artifacts/html-report",
63+
"open": "never"
64+
}
65+
]
66+
],
67+
"reportSlowTests": {
68+
"max": 5,
69+
"threshold": 300000
70+
},
71+
"shard": null,
72+
"tags": [],
73+
"updateSnapshots": "missing",
74+
"updateSourceMethod": "patch",
75+
"version": "1.59.1",
76+
"workers": 5,
77+
"webServer": null
78+
},
79+
"suites": [],
80+
"errors": [
81+
{
82+
"message": "Error: Command failed: npx wp-env run tests-cli --quiet -- wp eval \"echo is_multisite() ? '1' : '0';\"\nℹ Starting '--quiet wp eval echo is_multisite() ? '1' : '0';' on the tests-cli container. \n\nservice \"tests-cli\" is not running\n✖ Command failed with exit code 1\nCommand failed with exit code 1\n",
83+
"stack": "Error: Command failed: npx wp-env run tests-cli --quiet -- wp eval \"echo is_multisite() ? '1' : '0';\"\nℹ Starting '--quiet wp eval echo is_multisite() ? '1' : '0';' on the tests-cli container. \n\nservice \"tests-cli\" is not running\n✖ Command failed with exit code 1\nCommand failed with exit code 1\n\n at wpEnvCli (/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/setup/global-setup.ts:18:18)\n at ensureMultisiteTopology (/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/setup/global-setup.ts:25:19)\n at globalSetup (/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/setup/global-setup.ts:77:3)",
84+
"location": {
85+
"file": "/Users/dennis.ploetner/Projects/Multisite-Language-Switcher/tests/playwright/setup/global-setup.ts",
86+
"column": 18,
87+
"line": 18
88+
},
89+
"snippet": "\u001b[90m at \u001b[39m../setup/global-setup.ts:18\n\n\u001b[0m \u001b[90m 16 |\u001b[39m\n \u001b[90m 17 |\u001b[39m \u001b[36mfunction\u001b[39m wpEnvCli(command\u001b[33m:\u001b[39m string)\u001b[33m:\u001b[39m string {\n\u001b[31m\u001b[1m>\u001b[22m\u001b[39m\u001b[90m 18 |\u001b[39m \u001b[36mreturn\u001b[39m execSync(\u001b[32m`npx wp-env run tests-cli --quiet -- ${command}`\u001b[39m\u001b[33m,\u001b[39m {\n \u001b[90m |\u001b[39m \u001b[31m\u001b[1m^\u001b[22m\u001b[39m\n \u001b[90m 19 |\u001b[39m encoding\u001b[33m:\u001b[39m \u001b[32m'utf8'\u001b[39m\u001b[33m,\u001b[39m\n \u001b[90m 20 |\u001b[39m stdio\u001b[33m:\u001b[39m [\u001b[32m'ignore'\u001b[39m\u001b[33m,\u001b[39m \u001b[32m'pipe'\u001b[39m\u001b[33m,\u001b[39m \u001b[32m'pipe'\u001b[39m]\u001b[33m,\u001b[39m\n \u001b[90m 21 |\u001b[39m })\u001b[33m.\u001b[39mtrim()\u001b[33m;\u001b[39m\u001b[0m"
90+
}
91+
],
92+
"stats": {
93+
"startTime": "2026-05-18T12:36:07.462Z",
94+
"duration": 1293.3,
95+
"expected": 0,
96+
"skipped": 0,
97+
"unexpected": 0,
98+
"flaky": 0
99+
}
100+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"status": "failed",
3+
"failedTests": []
4+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { request } from '@playwright/test';
2+
import {
3+
test as base,
4+
expect,
5+
RequestUtils,
6+
} from '@wordpress/e2e-test-utils-playwright';
7+
import * as path from 'node:path';
8+
9+
export type SubsiteSlug = '' | 'de' | 'it';
10+
11+
const BASE_URL = process.env.WP_BASE_URL ?? 'http://localhost:8889';
12+
const STORAGE_STATE_DIR =
13+
process.env.STORAGE_STATE_DIR ??
14+
path.join(__dirname, '..', 'artifacts', 'storage-states');
15+
16+
function subsiteUrl(slug: SubsiteSlug): string {
17+
return slug === '' ? BASE_URL : `${BASE_URL}/${slug}`;
18+
}
19+
20+
function storageStatePath(slug: SubsiteSlug): string {
21+
const name = slug === '' ? 'admin' : `admin-${slug}`;
22+
return path.join(STORAGE_STATE_DIR, `${name}.json`);
23+
}
24+
25+
type MslsFixtures = {
26+
requestUtilsForBlog: (slug: SubsiteSlug) => Promise<RequestUtils>;
27+
};
28+
29+
export const test = base.extend<MslsFixtures>({
30+
requestUtilsForBlog: async ({}, use) => {
31+
const instances = new Map<SubsiteSlug, RequestUtils>();
32+
33+
const factory = async (slug: SubsiteSlug): Promise<RequestUtils> => {
34+
const cached = instances.get(slug);
35+
if (cached) {
36+
return cached;
37+
}
38+
39+
const ctx = await request.newContext({ baseURL: subsiteUrl(slug) });
40+
const utils = new RequestUtils(ctx, {
41+
baseURL: subsiteUrl(slug),
42+
storageStatePath: storageStatePath(slug),
43+
});
44+
await utils.setupRest();
45+
46+
instances.set(slug, utils);
47+
return utils;
48+
};
49+
50+
await use(factory);
51+
52+
for (const utils of instances.values()) {
53+
await utils.request.dispose();
54+
}
55+
},
56+
});
57+
58+
export { expect };

0 commit comments

Comments
 (0)