Files
CustomBranding/tests/BrandingConfig.test.js
Torsten Brendgen 490e9adbd8 feat: Add custom branding functionality with CSS and JSON configuration
- Introduced custom branding CSS styles in `custom-branding.css`.
- Created example JSON configuration for custom branding in `custom-branding.example.json`.
- Implemented branding configuration logic in `BrandingConfig.ts` to normalize and validate branding settings.
- Developed CSS loader to manage loading and unloading of custom stylesheets in `BrandingCssLoader.ts`.
- Added DOM rendering capabilities for branding elements in `BrandingDomRenderer.ts`.
- Defined types and interfaces for branding elements and configurations in `BrandingTypes.ts`.
- Included localization support for German in `de-de.js`.
- Added unit tests for branding configuration, CSS loader, and DOM renderer.
- Validated project structure and static assets with new validation scripts.
2026-07-20 22:55:47 +02:00

86 lines
3.9 KiB
JavaScript

'use strict';
var configModule = require('../temp/tests/BrandingConfig');
var normalize = configModule.normalizeBrandingConfig;
var siteUrl = 'http://sharepoint/sites/portal';
var passed = 0;
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
passed++;
}
function element(raw) {
return normalize({ placeholdertop: { elements: [raw] } }, siteUrl).config.placeholdertop.elements[0];
}
var empty = normalize({}, siteUrl);
assert(empty.config.schemaVersion === 2, 'Das aktuelle Schema muss Version 2 verwenden.');
assert(empty.config.enabled === true, 'Branding muss standardmaessig aktiviert sein.');
var legacy = normalize({ elements: [{ type: 'span', content: 'Alt' }] }, siteUrl);
assert(legacy.config.placeholdertop.elements.length === 1, 'Das Legacy-Root-Array muss weiter funktionieren.');
['div', 'span', 'p', 'a', 'button', 'img', 'h1', 'h2', 'h3', 'strong', 'em', 'nav', 'section']
.forEach(function (tag) {
var attributes = tag === 'img' ? { alt: '' } : undefined;
var content = tag === 'a' || tag === 'button' ? tag : undefined;
assert(!!element({ type: tag, content: content, attributes: attributes }), 'Erlaubter Tag fehlt: ' + tag);
});
assert(!element({ type: 'script', content: 'alert(1)' }), 'script darf nicht gerendert werden.');
assert(!element({ type: 'iframe' }), 'iframe darf nicht gerendert werden.');
var safeLink = element({
type: 'a',
content: 'Portal',
attributes: { href: '~sitecollection/SitePages/Home.aspx', target: '_blank', onclick: 'alert(1)' }
});
assert(safeLink.attributes.href === siteUrl + '/SitePages/Home.aspx', '~sitecollection wurde nicht aufgeloest.');
assert(safeLink.attributes.rel === 'noopener noreferrer', 'Externe Fenster brauchen noopener/noreferrer.');
assert(safeLink.attributes.onclick === undefined, 'Event-Attribute duerfen nicht uebernommen werden.');
var unsafeLink = element({ type: 'a', content: 'Unsicher', attributes: { href: 'javascript:alert(1)' } });
assert(unsafeLink.attributes === undefined || unsafeLink.attributes.href === undefined, 'javascript: muss blockiert werden.');
var styled = element({
type: 'div',
styles: { color: '#fff', position: 'fixed', background: 'url(javascript:alert(1))' }
});
assert(styled.styles.color === '#fff', 'Erlaubte Styles muessen erhalten bleiben.');
assert(styled.styles.position === undefined, 'Nicht freigegebene Styles muessen entfernt werden.');
assert(styled.styles.background === undefined, 'CSS url() muss blockiert werden.');
assert(!element({ type: 'img', attributes: { src: '/logo.png' } }), 'Bilder ohne alt muessen verworfen werden.');
assert(!!element({ type: 'img', attributes: { src: '/logo.png', alt: '' } }), 'Dekorative Bilder mit leerem alt sind erlaubt.');
assert(!element({ type: 'button' }), 'Leere Buttons muessen verworfen werden.');
var css = normalize({
allowedCssHosts: ['cdn.example.org'],
cssfiles: [
{ path: '/SiteAssets/site.css' },
{ path: 'https://cdn.example.org/portal.css', media: 'screen' },
{ path: 'https://evil.example.org/evil.css' },
{ path: 'http://cdn.example.org/mixed.css' },
{ path: '/SiteAssets/site.css' }
]
}, siteUrl).config.cssfiles;
assert(css.length === 2, 'CSS-Allowlist oder Deduplizierung ist fehlerhaft.');
assert(css[0].media === 'all' && css[1].media === 'screen', 'CSS-Media wurde nicht normalisiert.');
var deep = { type: 'div' };
var cursor = deep;
for (var depth = 0; depth < 12; depth++) {
cursor.children = [{ type: 'div' }];
cursor = cursor.children[0];
}
var deepResult = normalize({ placeholdertop: { elements: [deep] } }, siteUrl);
assert(deepResult.warnings.some(function (warning) { return warning.indexOf('depth') >= 0; }), 'Das Tiefenlimit greift nicht.');
var huge = { placeholdertop: { elements: [] }, padding: new Array(100002).join('x') };
assert(normalize(huge, siteUrl).config.placeholdertop.elements.length === 0, 'Zu grosse Konfiguration muss ignoriert werden.');
console.log('BrandingConfig: ' + passed + ' Pruefungen erfolgreich.');