Updated tests with localization
This commit is contained in:
Vendored
+2
-2
@@ -59,6 +59,6 @@ test('Android start hint distinguishes Chrome from other Android browsers', asyn
|
||||
assert.match(loader, /getElementById\('android-browser-hint'\)/);
|
||||
assert.match(loader, /\/Android\/i/);
|
||||
assert.match(loader, /\/Chrome\\\//i);
|
||||
assert.match(loader, /Auf diesem Gerät kannst du Bilder und Tonaufnahmen direkt auswählen/);
|
||||
assert.match(loader, /Tipp für Android: Mit Chrome/);
|
||||
assert.match(loader, /I18n\.t\("bootstrap-loader\.auf\.diesem\.gerat\.kannst\.du\.bilder\.und"\)/);
|
||||
assert.match(loader, /I18n\.t\("bootstrap-loader\.tipp\.fur\.android\.mit\.chrome\.lassen\.sich"\)/);
|
||||
});
|
||||
|
||||
+7
-3
@@ -26,18 +26,22 @@ test('language changes translate visible and spoken labels through textContent a
|
||||
const i18n = await loadI18n({});
|
||||
const make = key => ({ textContent: '', attributes: new Map(key), getAttribute(name) { return this.attributes.get(name); }, setAttribute(name, value) { this.attributes.set(name, value); } });
|
||||
const text = make([['data-i18n', 'app.strecke.wahlen']]);
|
||||
const label = make([['data-i18n-aria-label', 'app.strecke.wahlen']]);
|
||||
const attributes = ['aria-label', 'title', 'placeholder', 'alt'];
|
||||
const labels = new Map(attributes.map(attribute => [attribute, make([[`data-i18n-${attribute}`, 'app.strecke.wahlen']])]));
|
||||
const root = { documentElement: {}, querySelectorAll(selector) {
|
||||
if (selector === '[data-i18n]') return [text];
|
||||
if (selector === '[data-i18n-aria-label]') return [label];
|
||||
for (const [attribute, label] of labels) {
|
||||
if (selector === `[data-i18n-${attribute}]`) return [label];
|
||||
}
|
||||
return [];
|
||||
} };
|
||||
i18n.apply(root);
|
||||
assert.equal(text.textContent, 'Strecke wählen');
|
||||
assert.equal(label.attributes.get('aria-label'), 'Strecke wählen');
|
||||
for (const [attribute, label] of labels) assert.equal(label.attributes.get(attribute), 'Strecke wählen');
|
||||
i18n.register('en', { 'app.strecke.wahlen': '<Choose a trail>' });
|
||||
i18n.setLanguage('en', root);
|
||||
assert.equal(text.textContent, '<Choose a trail>');
|
||||
for (const [attribute, label] of labels) assert.equal(label.attributes.get(attribute), '<Choose a trail>');
|
||||
assert.equal(root.documentElement.lang, 'en');
|
||||
assert.equal(text.attributes.get('data-i18n'), 'app.strecke.wahlen');
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ test('start screen exposes cookie status, optional local progress and deliberate
|
||||
assert.match(html, /role="switch"[^>]*aria-checked="false"/);
|
||||
assert.match(html, /id="storage-cleanup-status"/);
|
||||
assert.match(html, /id="bootstrap-enter"[^>]*hidden/);
|
||||
assert.match(loader, /Alten Fortschritt löschen \(\{value1\} \/ \{value2\}\)/);
|
||||
assert.match(loader, /I18n\.t\("bootstrap-loader\.alten\.fortschritt\.loschen", \{ value1: removed, value2: total \}\)/);
|
||||
assert.match(loader, /showReadyState\(\)/);
|
||||
assert.doesNotMatch(loader, /getElementById\('bootstrap-screen'\)\.hidden = true/);
|
||||
assert.match(loader, /event\.target\.closest\('button, input, label, a, dialog'\)/);
|
||||
|
||||
@@ -153,7 +153,7 @@ test('Stationen have live direction and metre indicators and take navigation pri
|
||||
assert.match(app, /function updatePoiIndicators\(position\)/);
|
||||
assert.match(app, /function nearestPendingPoi\(metrics\)/);
|
||||
assert.match(app, /if \(nextPoi\) showPoiNavigation\(position, nextPoi\)/);
|
||||
assert.match(app, /Nächste Station:/);
|
||||
assert.match(app, /I18n\.t\("app\.nachste\.station\.2", \{ value1: metric\.poi\.title \}\)/);
|
||||
assert.match(app, /find\('small'\)\.text\(`\$\{distance\} m`\)/);
|
||||
assert.match(app, /find\('svg'\)\.css\('transform'/);
|
||||
assert.match(css, /\.poi-proximity[\s\S]*grid-column:\s*2/);
|
||||
|
||||
@@ -400,7 +400,10 @@ test('storage gauge uses browser estimate, separates Local Storage and reports q
|
||||
const usage = context.Wegwichtel.StorageUsage;
|
||||
await usage.refresh();
|
||||
assert.equal(elements.get('[data-storage-site-meter]').value, 95 * 1024 * 1024);
|
||||
assert.match(elements.get('[data-storage-site-text]').textContent, /95 %.*5,2 MB frei.*Fast voll/);
|
||||
const freeSpace = (5 * 1024 * 1024 / 1000000).toLocaleString('de', { maximumFractionDigits: 1 });
|
||||
const siteText = elements.get('[data-storage-site-text]').textContent;
|
||||
assert.match(siteText, /95 %.*Fast voll/);
|
||||
assert.ok(siteText.includes(`${freeSpace} MB frei`), siteText);
|
||||
assert.match(elements.get('[data-storage-local-text]').textContent, /Richtwert.*wirklich hineinpasst/);
|
||||
usage.reportError({ cause: { name: 'QuotaExceededError' } });
|
||||
await usage.refresh();
|
||||
@@ -409,3 +412,34 @@ test('storage gauge uses browser estimate, separates Local Storage and reports q
|
||||
await usage.refresh();
|
||||
assert.equal(elements.get('[data-storage-site-meter]').hidden, true);
|
||||
});
|
||||
|
||||
test('storage gauge uses the selected language with both localized and fallback number formatting', async () => {
|
||||
const source = await fs.readFile(path.join(root, 'public/js/storage-usage.js'), 'utf8');
|
||||
for (const decimalSeparator of [',', '.']) {
|
||||
const label = {};
|
||||
const calls = [];
|
||||
const context = {
|
||||
document: { querySelectorAll: selector => selector === '[data-storage-usage]' ? [{
|
||||
querySelector: selector => selector === '[data-storage-site-text]' ? label : null
|
||||
}] : [] },
|
||||
navigator: { storage: { estimate: async () => ({ usage: 95 * 1024 * 1024, quota: 100 * 1024 * 1024 }) } },
|
||||
formatNumber(value, language, options) {
|
||||
calls.push({ value, language, options });
|
||||
return value.toFixed(1).replace('.', decimalSeparator);
|
||||
}
|
||||
};
|
||||
const i18n = await loadI18n(context);
|
||||
// Model a runner whose Intl data falls back to a dot, without changing host globals.
|
||||
vm.runInNewContext('Number.prototype.toLocaleString = function (language, options) { return formatNumber(Number(this), language, options); };', context);
|
||||
vm.runInNewContext(source, context);
|
||||
await context.Wegwichtel.StorageUsage.refresh();
|
||||
assert.ok(label.textContent.includes(`5${decimalSeparator}2 MB frei`));
|
||||
assert.equal(calls[0].language, 'de');
|
||||
assert.equal(calls[0].options.maximumFractionDigits, 1);
|
||||
assert.equal(calls[0].value, 5 * 1024 * 1024 / 1000000);
|
||||
i18n.register('en', {});
|
||||
i18n.setLanguage('en', null);
|
||||
await context.Wegwichtel.StorageUsage.refresh();
|
||||
assert.equal(calls.at(-1).language, 'en');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@ test('persistent route control displays the next unvisited Station and preserves
|
||||
const app = await read('public/js/app.js');
|
||||
|
||||
assert.match(app, /function nextPoiMetric\(/);
|
||||
assert.match(app, /Nächste Station:/);
|
||||
assert.match(app, /I18n\.t\("app\.nachste\.station", \{ value1: metric\.poi\.title, value2: distance \}\)/);
|
||||
assert.match(app, /state\.triggered\.has\(poi\.id\)/);
|
||||
assert.match(app, /function suspendCurrentRoute\(/);
|
||||
assert.match(app, /persistRouteProgress\(\)/);
|
||||
|
||||
Reference in New Issue
Block a user