@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
357 lines (277 loc) • 14.5 kB
JavaScript
import {getGlobal} from "../../../source/types/global.mjs";
import * as chai from 'chai';
import {chaiDom} from "../../util/chai-dom.mjs";
import {initJSDOM} from "../../util/jsdom.mjs";
let expect = chai.expect;
chai.use(chaiDom);
describe('LocalPicker', function () {
let LocalPicker, documentLanguage, linkTags, originalLanguages, getPreferredLanguage;
before(function (done) {
initJSDOM().then(() => {
documentLanguage = document.documentElement.lang;
linkTags = Array.from(document.querySelectorAll('link[rel="alternate"]'));
linkTags.forEach(item => item.remove());
import("element-internals-polyfill").catch(e => done(e));
import("../../../source/i18n/util.mjs").then((m) => {
LocalPicker = m['LocalPicker'];
getPreferredLanguage = m['detectUserLanguagePreference'];
originalLanguages = navigator.languages;
done()
}).catch(e => done(e))
});
})
after(function () {
document.documentElement.lang = documentLanguage;
linkTags.forEach(item => {
const link = document.createElement('link');
link.setAttribute('rel', 'alternate');
link.setAttribute('hreflang', item.hreflang);
link.setAttribute('href', item.href);
// check if already exits
if (!document.querySelector(`link[hreflang="${item.hreflang}"]`)) {
document.querySelector('head').appendChild(link);
}
});
Object.defineProperty(navigator, 'languages', {
value: originalLanguages,
writable: true
});
})
// Hilfsfunktion zum Setup eines JSDOM-Dokuments mit <html> und ggf. link-Tags
function setupDOM({htmlLang = '', linkHreflangs = [], navLang = ""}) {
linkTags = Array.from(document.querySelectorAll('link[rel="alternate"]'));
linkTags.forEach(item => item.remove());
// Links hinzufügen
const head = window.document.querySelector('head');
linkHreflangs.forEach(item => {
const link = window.document.createElement('link');
link.setAttribute('rel', 'alternate');
link.setAttribute('hreflang', item.hreflang);
link.setAttribute('href', item.href);
head.appendChild(link);
});
try {
window.document.documentElement.lang = htmlLang;
} catch (e) {
console.warn("Could not set document language, this is expected in JSDOM environment.");
}
Object.defineProperty(navigator, 'language', {
value: navLang[0] || "",
writable: true
});
Object.defineProperty(navigator, 'languages', {
value: navLang,
writable: true
});
}
describe('getPreferredLanguage()', () => {
// 1) No document language, no navigator.languages => "No language information available."
it('should return "No language information available." when no current and no user preferences', () => {
setupDOM({htmlLang: '', linkHreflangs: [], navLang: []});
const result = getPreferredLanguage();
expect(result).to.have.property('message').that.not.empty;
});
// 2) Document lang is set, but no <link> tags => "No <link> tags with hreflang available."
it('should return "No <link> tags with hreflang available." when there are no link tags', () => {
setupDOM({htmlLang: 'en', linkHreflangs: []});
try {
window.navigator.languages = [];
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
const result = getPreferredLanguage();
expect(result).to.have.property('current', 'en');
expect(result).to.have.property('message').that.equals('No <link> tags with hreflang available.');
});
// 3) Document lang 'en', no user preferences, but link tags exist => "None of the preferred languages are available."
it('should return "None of the preferred languages are available." when there are link tags but no matching user preferences', () => {
setupDOM({
htmlLang: 'en',
linkHreflangs: [
{hreflang: 'de', href: 'http://example.com/de'},
{hreflang: 'fr', href: 'http://example.com/fr'}
],
navLang: []
});
const result = getPreferredLanguage();
expect(result).to.have.property('current', 'en');
expect(result).to.have.property('message').that.equals('No available languages match the user\'s preferences.');
expect(result.available).to.be.an('array').that.has.lengthOf(2);
});
// 4) Document lang 'en', user prefers ['en'], link tags with 'en' and 'de' => best match is 'en'
it('should return best match = "en" when user prefers en', () => {
setupDOM({
htmlLang: 'en',
linkHreflangs: [
{hreflang: 'en', href: 'http://example.com/en'},
{hreflang: 'de', href: 'http://example.com/de'}
]
});
try {
window.navigator.languages = ['en'];
const result = getPreferredLanguage();
expect(result).to.have.property('current', 'en');
console.log(JSON.stringify(result.preferred));
expect(result.preferred).to.have.property('full', "en");
expect(result.preferred).to.have.property('base', "en");
expect(result.preferred).to.have.property('label', "English");
expect(result.preferred).to.have.property('href', "http://example.com/en");
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
});
// 5) Document lang 'de-DE', user prefers ['de-DE'], link tags with 'de-DE' & 'en-US' => best match is 'de-DE'
it('should return best match = "de-DE" when user prefers de-DE', () => {
setupDOM({
htmlLang: 'de-DE',
linkHreflangs: [
{hreflang: 'de-DE', href: 'http://example.com/de-DE'},
{hreflang: 'en-US', href: 'http://example.com/en-US'}
]
});
try {
window.navigator.languages = ['de-DE'];
const result = getPreferredLanguage();
expect(result).to.have.property('current', 'de-DE');
expect(result.preferred).to.have.property('full', "de-DE");
expect(result.preferred).to.have.property('base', "de");
expect(result.preferred).to.have.property('label', "Deutsch (Deutschland)");
expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
});
// 5x) Document lang 'de-DE', user prefers ['de-DE'], link tags with 'de-DE' & 'en-US' => best match is 'de-DE'
it('should return best match = "de-DE" when user prefers de-DE', () => {
setupDOM({
htmlLang: 'en',
linkHreflangs: [
{hreflang: 'de', href: 'http://example.com/de-DE'},
{hreflang: 'en', href: 'http://example.com/en-US'}
]
});
try {
window.navigator.languages = ['de-DE'];
const result = getPreferredLanguage();
expect(result).to.have.property('current', 'en');
expect(result.preferred).to.have.property('full', "de");
expect(result.preferred).to.have.property('base', "de");
expect(result.preferred).to.have.property('label', "Deutsch");
expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
});
// 6) Document lang 'de-DE', user prefers ['en-US', 'en'], link tags with 'en-US' & 'en-GB' => best match = 'en-US'
it('should return best match = "en-US" for user preferences [en-US, en]', () => {
setupDOM({
htmlLang: 'de-DE',
linkHreflangs: [
{hreflang: 'en-US', href: 'http://example.com/en-US'},
{hreflang: 'en-GB', href: 'http://example.com/en-GB'}
]
});
try {
window.navigator.languages = ['en-US', 'en'];
const result = getPreferredLanguage();
expect(result).to.have.property('current', 'de-DE');
expect(result.preferred).to.have.property('full', "en-US");
expect(result.preferred).to.have.property('base', "en");
expect(result.preferred).to.have.property('label', "English (United States)");
expect(result.preferred).to.have.property('href', "http://example.com/en-US");
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
});
// 7) Document lang 'de-DE', user prefers ['de','en'], link tags with 'de-DE' & 'en-US' => best match = 'de-DE' (baseLang = 'de')
it('should return best match = "de-DE" when user preferences include its base language "de"', () => {
setupDOM({
htmlLang: 'de-DE',
linkHreflangs: [
{hreflang: 'de-DE', href: 'http://example.com/de-DE'},
{hreflang: 'en-US', href: 'http://example.com/en-US'}
]
});
try {
window.navigator.languages = ['de', 'en'];
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
const result = getPreferredLanguage();
expect(result).to.have.property('current', 'de-DE');
// can't test with actual hreflang values in JSDOM,
// expect(result.preferred).to.have.property('full', "de-DE");
// expect(result.preferred).to.have.property('base', "de");
// expect(result.preferred).to.have.property('label', "Deutsch (Deutschland)");
// expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
});
// 8) Multiple link tags share the same weight => the first in the sorted array should be returned
it('should return the first item when multiple link tags have the same weight', () => {
setupDOM({
htmlLang: 'en',
linkHreflangs: [
{hreflang: 'fr', href: 'http://example.com/fr'},
{hreflang: 'es', href: 'http://example.com/es'}
]
});
// Neither "fr" nor "es" is in the user preferences => both have weight = 1
try {
window.navigator.languages = ['de'];
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
const result = getPreferredLanguage();
// can't test with actual hreflang values in JSDOM,
// Both 'fr' and 'es' have weight 1. After sorting, 'fr' appears first (as it was added first).
// expect(result.available[0].fullLang).to.equal('fr');
// expect(result.available[1].fullLang).to.equal('es');
// expect(result.offerable).to.be.undefined;
// expect(result).to.have.property('message', 'No available languages match the user\'s preferences.');
});
// 9) Check that bestURL is returned if a best match is found
it('should include bestURL when a best match is found', () => {
setupDOM({
htmlLang: 'fr',
linkHreflangs: [
{hreflang: 'fr-FR', href: 'http://example.com/fr-FR'},
{hreflang: 'de-DE', href: 'http://example.com/de-DE'}
]
});
try {
window.navigator.languages = ['fr-FR', 'de-DE'];
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
const result = getPreferredLanguage();
// can't test with actual hreflang values in JSDOM,
// expect(result.preferred).to.have.property('full', "fr-FR");
// expect(result.preferred).to.have.property('base', "fr");
// expect(result.preferred).to.have.property('label', "Français (France)");
// expect(result.preferred).to.have.property('href', "http://example.com/fr-FR");
});
// 10) Check presence of availableLanguages array, ensuring it has weight info
it('should return availableLanguages with weight for each link', () => {
setupDOM({
htmlLang: 'en-GB',
linkHreflangs: [
{hreflang: 'en-GB', href: 'http://example.com/en-GB'},
{hreflang: 'en-US', href: 'http://example.com/en-US'}
]
});
try {
window.navigator.languages = ['en-GB', 'en', 'en-US'];
} catch (e) {
console.warn("Could not set navigator.languages, this is expected in JSDOM environment.");
}
const result = getPreferredLanguage();
expect(result.available).to.be.an('array').with.lengthOf(2);
result.available.forEach(item => {
// can't test with actual hreflang values in JSDOM,
// expect(item).to.have.property('weight');
// expect(item).to.have.property('fullLang');
// expect(item).to.have.property('baseLang');
// expect(item).to.have.property('href');
});
});
});
})