UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

357 lines (277 loc) 14.5 kB
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'); }); }); }); })