Skip to content

Commit 14175e2

Browse files
committed
docs: Add language-agnostic for Playwright testing doc
1 parent 40be023 commit 14175e2

File tree

1 file changed

+375
-0
lines changed

1 file changed

+375
-0
lines changed
Lines changed: 375 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
---
2+
nav:
3+
title: Language Agnostic Testing
4+
position: 20
5+
---
6+
7+
# Language Agnostic Testing in @shopware-ag/acceptance-test-suite
8+
9+
Language agnostic testing allows you to write acceptance tests that work across different languages without hardcoding text strings. Tests use translation keys instead of hardcoded strings and automatically adapt to different locales via environment variables.
10+
11+
## translate() Function
12+
13+
Use the `translate()` function in page objects to replace hardcoded strings with translation keys.
14+
15+
### Usage in Page Objects
16+
17+
```typescript
18+
import { translate } from '../../services/LanguageHelper';
19+
20+
export class CategoryListing implements PageObject {
21+
constructor(page: Page) {
22+
this.createButton = page.getByRole('button', {
23+
name: translate('administration:category:actions.createCategory'),
24+
});
25+
}
26+
}
27+
```
28+
29+
## Translate Fixture
30+
31+
The `Translate` fixture provides translation functionality in tests.
32+
33+
### Usage in Tests
34+
35+
```typescript
36+
import { test, expect } from '@shopware-ag/acceptance-test-suite';
37+
38+
test('Category creation', async ({ AdminPage, Translate }) => {
39+
const saveText = Translate('administration:category:general.save');
40+
await AdminPage.getByRole('button', { name: saveText }).click();
41+
});
42+
```
43+
44+
## Environment Control
45+
46+
Switch test language using environment variables:
47+
48+
```bash
49+
LANG=de npm run test # German
50+
LANG=en npm run test # English (default)
51+
```
52+
53+
## Translation Keys
54+
55+
Translation keys follow the pattern: `area:module:section.key`
56+
57+
### Examples
58+
59+
```typescript
60+
'administration:category:general.save';
61+
'administration:category:actions.createCategory';
62+
'storefront:account:fields.firstName';
63+
'storefront:checkout:payment.invoice';
64+
```
65+
66+
### Locale Files
67+
68+
Translations are stored in JSON files organized by language and area:
69+
70+
- `locales/en/administration/category.json`
71+
- `locales/de/administration/category.json`
72+
- `locales/en/storefront/account.json`
73+
- `locales/de/storefront/account.json`
74+
75+
### Example Translation Files
76+
77+
**English (`locales/en/administration/category.json`):**
78+
79+
```json
80+
{
81+
"general": {
82+
"save": "Save",
83+
"cancel": "Cancel"
84+
},
85+
"actions": {
86+
"createCategory": "Create category"
87+
}
88+
}
89+
```
90+
91+
**German (`locales/de/administration/category.json`):**
92+
93+
```json
94+
{
95+
"general": {
96+
"save": "Speichern",
97+
"cancel": "Abbrechen"
98+
},
99+
"actions": {
100+
"createCategory": "Kategorie erstellen"
101+
}
102+
}
103+
```
104+
105+
## Supported Locales
106+
107+
**Translation Resources**: `en` (English), `de` (German)
108+
**Browser UI**: `en`, `de`, `fr`, `es`, `it`, `nl`, `pt`
109+
110+
## Common Issues
111+
112+
**Translation key not found:**
113+
114+
- Verify key exists in both EN/DE locale files
115+
- Check import in `locales/index.ts`
116+
- Ensure proper namespace structure
117+
118+
**Tests fail with LANG changes:**
119+
120+
- Move `translate()` calls inside constructors/functions, not at module level
121+
- Ensure translation resources are properly loaded
122+
123+
**JSON import errors:**
124+
125+
- Always use `with { type: 'json' }` import attribute
126+
- Check file paths and naming conventions
127+
128+
**Browser locale not matching:**
129+
130+
- Verify locale mapping in `playwright.config.ts`
131+
- Check browser args configuration
132+
- Ensure language detection is working correctly
133+
134+
## Using in Your Own Project
135+
136+
If you want to use the `@shopware-ag/acceptance-test-suite` in your own project with custom translations, you can extend the base test suite with your own translation fixture.
137+
138+
### Installation
139+
140+
First, install the required dependencies:
141+
142+
```bash
143+
npm install @shopware-ag/acceptance-test-suite @playwright/test
144+
npm install -D @types/node
145+
```
146+
147+
### Create Custom Translation Fixture
148+
149+
Create a new fixture file (e.g., `fixtures/CustomTranslation.ts`):
150+
151+
```typescript
152+
import {
153+
test as base,
154+
LanguageHelper,
155+
TranslationKey,
156+
TranslateFn,
157+
BUNDLED_RESOURCES,
158+
baseNamespaces,
159+
} from '@shopware-ag/acceptance-test-suite';
160+
import { LOCALE_RESOURCES, enNamespaces } from '../locales';
161+
162+
// Merge base BUNDLED_RESOURCES with your custom LOCALE_RESOURCES
163+
const MERGED_RESOURCES = {
164+
en: { ...BUNDLED_RESOURCES.en, ...LOCALE_RESOURCES.en },
165+
de: { ...BUNDLED_RESOURCES.de, ...LOCALE_RESOURCES.de },
166+
} as const;
167+
168+
// Merge base and custom namespaces
169+
const mergedNamespaces = {
170+
...baseNamespaces,
171+
...enNamespaces,
172+
} as const;
173+
174+
type CustomTranslationKey = TranslationKey<typeof mergedNamespaces>;
175+
176+
interface CustomTranslateFixture {
177+
Translate: TranslateFn<CustomTranslationKey>;
178+
}
179+
180+
export const test = base.extend<CustomTranslateFixture>({
181+
Translate: async ({}, use) => {
182+
let lang = process.env.lang || process.env.LANGUAGE || process.env.LANG || 'en';
183+
let language = lang.split(/[_.-]/)[0].toLowerCase();
184+
185+
if (!MERGED_RESOURCES[language as keyof typeof MERGED_RESOURCES]) {
186+
console.warn(
187+
`⚠️ Translation resources for '${language}' not available. Supported: ${Object.keys(
188+
MERGED_RESOURCES
189+
).join(', ')}. Falling back to 'en'.`
190+
);
191+
language = 'en';
192+
}
193+
194+
const languageHelper = await LanguageHelper.createInstance(
195+
language,
196+
MERGED_RESOURCES as unknown as typeof BUNDLED_RESOURCES
197+
);
198+
199+
const translate: TranslateFn<CustomTranslationKey> = (key, options) => {
200+
return languageHelper.translate(key as TranslationKey, options);
201+
};
202+
203+
await use(translate);
204+
},
205+
});
206+
207+
export * from '@shopware-ag/acceptance-test-suite';
208+
export type { CustomTranslationKey };
209+
```
210+
211+
### Create Locale Files Structure
212+
213+
Organize your translation files by language and area:
214+
215+
```
216+
project-root/
217+
├── locales/
218+
│ ├── en/
219+
│ │ ├── administration/
220+
│ │ │ ├── common.json
221+
│ │ │ └── product.json
222+
│ │ └── storefront/
223+
│ │ ├── account.json
224+
│ │ └── checkout.json
225+
│ ├── de/
226+
│ │ ├── administration/
227+
│ │ │ ├── common.json
228+
│ │ │ └── product.json
229+
│ │ └── storefront/
230+
│ │ ├── account.json
231+
│ │ └── checkout.json
232+
│ └── index.ts
233+
├── fixtures/
234+
│ └── CustomTranslation.ts
235+
├── types/
236+
│ └── TranslationTypes.ts
237+
└── tests/
238+
└── your-test.spec.ts
239+
```
240+
241+
### Create Locales Index
242+
243+
Create `locales/index.ts` to import and export your translation files:
244+
245+
```typescript
246+
// Import all locale files
247+
import enAdministrationCommon from './en/administration/common.json' with { type: 'json' };
248+
import enStorefrontAccount from './en/storefront/account.json' with { type: 'json' };
249+
250+
import deAdministrationCommon from './de/administration/common.json' with { type: 'json' };
251+
import deStorefrontAccount from './de/storefront/account.json' with { type: 'json' };
252+
253+
// Export the bundled resources for i18next
254+
export const LOCALE_RESOURCES = {
255+
en: {
256+
'administration/common': enAdministrationCommon,
257+
'storefront/account': enStorefrontAccount,
258+
},
259+
de: {
260+
'administration/common': deAdministrationCommon,
261+
'storefront/account': deStorefrontAccount,
262+
},
263+
} as const;
264+
265+
export const enNamespaces = {
266+
administration: {
267+
common: enAdministrationCommon,
268+
},
269+
storefront: {
270+
account: enStorefrontAccount,
271+
},
272+
} as const;
273+
```
274+
275+
### Create Translation Types
276+
277+
Create `types/TranslationTypes.ts` to define your custom translation types. This provides:
278+
279+
- **Type Safety**: Ensures translation keys exist in your locale files
280+
- **IntelliSense**: Auto-completion for available translation keys
281+
- **Compile-time Validation**: Catches typos and missing keys before runtime
282+
283+
```typescript
284+
import { TranslationKey, TranslateFn } from '@shopware-ag/acceptance-test-suite';
285+
import { enNamespaces } from '../locales';
286+
287+
export type CustomTranslationKey = TranslationKey<typeof enNamespaces>;
288+
289+
export type CustomTranslateFn = TranslateFn<CustomTranslationKey>;
290+
```
291+
292+
### Merge with Base Test Suite
293+
294+
Create your main test fixture that merges the base test suite with your custom translation:
295+
296+
```typescript
297+
import { test as ShopwareTestSuite, mergeTests } from '@shopware-ag/acceptance-test-suite';
298+
import { test as CustomTranslation } from './fixtures/CustomTranslation';
299+
300+
export * from '@shopware-ag/acceptance-test-suite';
301+
302+
export const test = mergeTests(ShopwareTestSuite, CustomTranslation);
303+
```
304+
305+
**Note**: Save this as `test.ts` or `index.ts` in your project root and import it in your test files.
306+
307+
### Usage in Your Tests
308+
309+
Now you can use the `Translate` fixture in your tests:
310+
311+
```typescript
312+
import { test } from './your-main-test-fixture';
313+
314+
test('My localized test', async ({ Translate, AdminPage }) => {
315+
const saveText = Translate('administration:common:button.save');
316+
await AdminPage.getByRole('button', { name: saveText }).click();
317+
});
318+
```
319+
320+
### Environment Configuration
321+
322+
Set up your Playwright configuration to support language switching:
323+
324+
```typescript
325+
// playwright.config.ts
326+
import { defineConfig, devices } from '@playwright/test';
327+
328+
const LOCALES = { de: 'de-DE', en: 'en-US', fr: 'fr-FR' };
329+
330+
function getLanguage(): string {
331+
let lang = process.env.lang || process.env.LANGUAGE || process.env.LANG || 'en';
332+
return lang.split(/[_.-]/)[0].toLowerCase();
333+
}
334+
335+
function getLocaleConfig() {
336+
const lang = getLanguage();
337+
const browserLocale = LOCALES[lang as keyof typeof LOCALES] || 'en-US';
338+
const browserArgs =
339+
lang !== 'en' && LOCALES[lang as keyof typeof LOCALES]
340+
? [`--lang=${browserLocale}`, `--accept-lang=${browserLocale},${lang};q=0.9,en;q=0.8`]
341+
: [];
342+
343+
return { lang, browserLocale, browserArgs };
344+
}
345+
346+
export default defineConfig({
347+
use: {
348+
locale: getLocaleConfig().browserLocale,
349+
},
350+
projects: [
351+
{
352+
name: 'Platform',
353+
use: {
354+
...devices['Desktop Chrome'],
355+
launchOptions: {
356+
args: [...getLocaleConfig().browserArgs],
357+
},
358+
},
359+
},
360+
],
361+
});
362+
```
363+
364+
### Running Tests with Different Languages
365+
366+
```bash
367+
# German
368+
lang=de npx playwright test
369+
370+
# English (default)
371+
npx playwright test
372+
373+
# Using system environment
374+
LANG=de npx playwright test
375+
```

0 commit comments

Comments
 (0)