diff --git a/client/src/linkManager.js b/client/src/linkManager.js index 7c6ddcbc4d..24cd96b635 100644 --- a/client/src/linkManager.js +++ b/client/src/linkManager.js @@ -383,8 +383,8 @@ export class linkManager extends LuigiClientBase { const currentId = helpers.getRandomId(); const pathExistsPromises = this.getPromise('pathExistsPromises') || {}; pathExistsPromises[currentId] = { - resolveFn: function() {}, - then: function(resolveFn) { + resolveFn: function () {}, + then: function (resolveFn) { this.resolveFn = resolveFn; } }; @@ -393,7 +393,7 @@ export class linkManager extends LuigiClientBase { // register event listener, which will be cleaned up after this usage helpers.addEventListener( 'luigi.navigation.pathExists.answer', - function(e, listenerId) { + function (e, listenerId) { const data = e.data.data; const pathExistsPromises = this.getPromise('pathExistsPromises') || {}; if (data.correlationId === currentId) { @@ -499,8 +499,8 @@ export class linkManager extends LuigiClientBase { const currentRoutePromise = this.getPromise('getCurrentRoute') || {}; currentRoutePromise[currentId] = { - resolveFn: function() {}, - then: function(resolveFn) { + resolveFn: function () {}, + then: function (resolveFn) { this.resolveFn = resolveFn; } }; diff --git a/client/src/uxManager.js b/client/src/uxManager.js index 47d12f85c5..a98e402355 100644 --- a/client/src/uxManager.js +++ b/client/src/uxManager.js @@ -10,7 +10,7 @@ class UxManager extends LuigiClientBase { /** @private */ constructor() { super(); - helpers.addEventListener('luigi.current-locale-changed', e => { + helpers.addEventListener('luigi.current-locale-changed', (e) => { if (e.data.currentLocale && lifecycleManager.currentContext?.internal) { lifecycleManager.currentContext.internal.currentLocale = e.data.currentLocale; lifecycleManager._notifyUpdate(); @@ -183,7 +183,7 @@ class UxManager extends LuigiClientBase { const alertPromises = this.getPromise('alerts') || {}; alertPromises[settings.id] = {}; - alertPromises[settings.id].promise = new Promise(resolve => { + alertPromises[settings.id].promise = new Promise((resolve) => { alertPromises[settings.id].resolveFn = resolve; }); this.setPromise('alerts', alertPromises); @@ -297,13 +297,13 @@ class UxManager extends LuigiClientBase { * @example LuigiClient.uxManager().applyCSS(); */ applyCSS() { - document.querySelectorAll('head style[luigi-injected]').forEach(luigiInjectedStyleTag => { + document.querySelectorAll('head style[luigi-injected]').forEach((luigiInjectedStyleTag) => { luigiInjectedStyleTag.remove(); }); const vars = lifecycleManager.currentContext?.internal?.cssVariables; if (vars) { let cssString = ':root {\n'; - Object.keys(vars).forEach(key => { + Object.keys(vars).forEach((key) => { const val = vars[key]; cssString += (key.startsWith('--') ? '' : '--') + key + ':' + val + ';\n'; }); diff --git a/container/cypress/e2e/test-app/compound/wc-compound-container.cy.js b/container/cypress/e2e/test-app/compound/wc-compound-container.cy.js index 942216cfec..76cd80d597 100644 --- a/container/cypress/e2e/test-app/compound/wc-compound-container.cy.js +++ b/container/cypress/e2e/test-app/compound/wc-compound-container.cy.js @@ -118,9 +118,7 @@ describe('Compound Container Tests', () => { }); it('LuigiClient API - getSkipInitCheck', () => { - cy.get(containerSelector) - .invoke('attr', 'skip-init-check') - .should('eq', 'true'); + cy.get(containerSelector).invoke('attr', 'skip-init-check').should('eq', 'true'); }); it('LuigiClient API - getActiveFeatureToggles', () => { @@ -188,7 +186,7 @@ describe('Compound Container Tests', () => { .contains('showConfirmationModal') .click() .then(() => { - cy.on('window:confirm', str => { + cy.on('window:confirm', (str) => { expect(str).to.equal('Are you sure you want to do this?'); }); expect(stub.getCall(0)).to.be.calledWith('LuigiClient.uxManager().showConfirmationModal()'); @@ -255,7 +253,7 @@ describe('Compound Container Tests', () => { cy.on('window:alert', stub); // Set up a spy on console.log - cy.window().then(win => { + cy.window().then((win) => { cy.spy(win.console, 'log').as('consoleLogSpy'); }); diff --git a/container/cypress/e2e/test-app/iframe/iframe-container.cy.js b/container/cypress/e2e/test-app/iframe/iframe-container.cy.js index fe2b83d177..a0358ddd91 100644 --- a/container/cypress/e2e/test-app/iframe/iframe-container.cy.js +++ b/container/cypress/e2e/test-app/iframe/iframe-container.cy.js @@ -24,13 +24,11 @@ describe('Iframe Container Test', () => { cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); - cy.wrap($body) - .contains('test navigate') - .click(); + cy.wrap($body).contains('test navigate').click(); - cy.location().should(loc => { + cy.location().should((loc) => { expect(loc.href).to.eq('http://localhost:8080/'); }); }); @@ -41,11 +39,9 @@ describe('Iframe Container Test', () => { cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); - cy.wrap($body) - .find('#content') - .should('have.text', 'Received Custom Message: some data'); + cy.wrap($body).find('#content').should('have.text', 'Received Custom Message: some data'); }); }); @@ -55,7 +51,7 @@ describe('Iframe Container Test', () => { cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); cy.wrap($body) .contains('test custom message') @@ -78,7 +74,7 @@ describe('Iframe Container Test', () => { cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); cy.wrap($body) @@ -102,7 +98,7 @@ describe('Iframe Container Test', () => { cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); cy.wrap($body) .contains('test get token') @@ -117,54 +113,48 @@ describe('Iframe Container Test', () => { }); it('openAsModal', () => { - cy.on('window:confirm', () => false); - + cy.on('window:confirm', () => false); + cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); - cy.wrap($body) - .contains('test openAsModal()') - .click(); - - cy.location().should(loc => { + cy.wrap($body).contains('test openAsModal()').click(); + + cy.location().should((loc) => { expect(loc.hash).to.eq('#openAsModal-iframe'); }); }); }); it('openAsDrawer', () => { - cy.on('window:confirm', () => false); - + cy.on('window:confirm', () => false); + cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); - cy.wrap($body) - .contains('test openAsDrawer') - .click(); - - cy.location().should(loc => { + cy.wrap($body).contains('test openAsDrawer').click(); + + cy.location().should((loc) => { expect(loc.hash).to.eq('#openAsDrawer-iframe'); }); }); }); it('openAsSplitview', () => { - cy.on('window:confirm', () => false); - + cy.on('window:confirm', () => false); + cy.get(containerSelector) .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); - cy.wrap($body) - .contains('test openAsSplitview') - .click(); - - cy.location().should(loc => { + cy.wrap($body).contains('test openAsSplitview').click(); + + cy.location().should((loc) => { expect(loc.hash).to.eq('#openAsSplitview-iframe'); }); }); diff --git a/container/cypress/e2e/test-app/iframe/iframe-cookies.cy.js b/container/cypress/e2e/test-app/iframe/iframe-cookies.cy.js index e9e5e8af1a..42ecc9357b 100644 --- a/container/cypress/e2e/test-app/iframe/iframe-cookies.cy.js +++ b/container/cypress/e2e/test-app/iframe/iframe-cookies.cy.js @@ -10,9 +10,7 @@ describe('Iframe Cookies Test', () => { it('should not sent third party cookies request', () => { cy.on('window:alert', stub); - cy.get(containerSelector) - .should('have.attr', 'skip-cookie-check') - .and('match', /true/); + cy.get(containerSelector).should('have.attr', 'skip-cookie-check').and('match', /true/); cy.get(containerSelector) .shadow() .get('iframe') diff --git a/container/cypress/e2e/test-app/iframe/iframe-settings.cy.js b/container/cypress/e2e/test-app/iframe/iframe-settings.cy.js index 1cfa540c4d..8f5c5dcbe5 100644 --- a/container/cypress/e2e/test-app/iframe/iframe-settings.cy.js +++ b/container/cypress/e2e/test-app/iframe/iframe-settings.cy.js @@ -7,7 +7,7 @@ describe('Iframe Settings Test', () => { }); it('defer-init flag for iframe container', () => { - cy.get('#defer-init-test').then(iframe => { + cy.get('#defer-init-test').then((iframe) => { const $body = iframe.contents().find('main'); expect($body.children()).to.have.length(0); @@ -17,11 +17,9 @@ describe('Iframe Settings Test', () => { cy.get('#defer-init-test') .shadow() .get('iframe') - .then(iframe => { + .then((iframe) => { const $body = iframe.contents().find('body'); - cy.wrap($body) - .contains('defer-init test for iframes') - .should('exist'); + cy.wrap($body).contains('defer-init test for iframes').should('exist'); }); }); }); @@ -33,10 +31,8 @@ describe('Iframe Settings Test', () => { cy.get('#defer-init-test') .shadow() .get('iframe') - .then(elements => { - cy.get(elements.first()) - .invoke('attr', 'sandbox') - .should('eq', 'allow-modals allow-popups'); + .then((elements) => { + cy.get(elements.first()).invoke('attr', 'sandbox').should('eq', 'allow-modals allow-popups'); }); }); @@ -44,10 +40,8 @@ describe('Iframe Settings Test', () => { cy.get('#sandbox-rules-test') .shadow() .find('iframe') - .then(elements => { - cy.get(elements.last()) - .invoke('attr', 'sandbox') - .should('eq', 'allow-scripts allow-same-origin'); + .then((elements) => { + cy.get(elements.last()).invoke('attr', 'sandbox').should('eq', 'allow-scripts allow-same-origin'); }); }); @@ -76,15 +70,11 @@ describe('Iframe Settings Test', () => { it('should initialize Luigi Client', () => { cy.get('iframe').then(($iframe) => { const iframeBody = $iframe.contents().find('body'); - + const checkLuigiClientStatus = (expectedStatus) => { - cy.wrap(iframeBody) - .find('#luigiClientStatus') - .should('exist') - .invoke('text') - .should('eq', expectedStatus); + cy.wrap(iframeBody).find('#luigiClientStatus').should('exist').invoke('text').should('eq', expectedStatus); }; - + checkLuigiClientStatus('Luigi Client Initialized: Unknown'); cy.wait(2000); checkLuigiClientStatus('Luigi Client Initialized: true'); diff --git a/container/cypress/e2e/test-app/wc/wc-container.cy.js b/container/cypress/e2e/test-app/wc/wc-container.cy.js index 5550e977c2..b13fa31bcb 100644 --- a/container/cypress/e2e/test-app/wc/wc-container.cy.js +++ b/container/cypress/e2e/test-app/wc/wc-container.cy.js @@ -133,10 +133,7 @@ describe('Web Container Test', () => { }); it('sendCustomMessage', () => { - cy.get(containerSelector) - .shadow() - .find('#customMessageDiv') - .should('have.text', 'Received Custom Message: '); + cy.get(containerSelector).shadow().find('#customMessageDiv').should('have.text', 'Received Custom Message: '); cy.get('#sendCustomMessageBtn').click(); cy.get(containerSelector) @@ -214,7 +211,7 @@ describe('Web Container Test', () => { .contains('showConfirmationModal') .click() .then(() => { - cy.on('window:confirm', str => { + cy.on('window:confirm', (str) => { expect(str).to.equal('Are you sure you want to do this?'); }); expect(stub.getCall(0)).to.be.calledWith('LuigiClient.uxManager().showConfirmationModal()'); diff --git a/container/generateCEM.js b/container/generateCEM.js new file mode 100644 index 0000000000..8fd34f853a --- /dev/null +++ b/container/generateCEM.js @@ -0,0 +1,375 @@ +const fs = require('fs'); +const path = require('path'); +const { parse } = require('@typescript-eslint/typescript-estree'); + +const luigiContainerPath = 'src/LuigiContainer.svelte'; +const luigiCompoundContainerPath = 'src/LuigiCompoundContainer.svelte'; +const luigiContainerTypingsPath = 'typings/LuigiContainer.svelte.d.ts'; +const luigiCompoundContainerTypingsPath = 'typings/LuigiCompoundContainer.svelte.d.ts'; +const luigiEventsPath = 'typings/constants/events.d.ts'; + +/** + * Parses a `props` object from the provided file content string. + * @param {string} fileContent - The content of the file as a string, which should contain a `props` object. + * @returns {Object} The parsed `props` object. + */ +function parseContainerProps(fileContent) { + if (!fileContent || fileContent === '') { + throw new Error('Cannot parse container props, fileContent is empty in parseContainerProps.'); + } + const propsIndex = fileContent.indexOf('props:'); + if (propsIndex === -1) { + throw new Error('No properties found.'); + } + + let openBraces = 0; + let propsStart = fileContent.indexOf('{', propsIndex); + let propsEnd = propsStart; + + for (let i = propsStart; i < fileContent.length; i++) { + if (fileContent[i] === '{') { + openBraces++; + } else if (fileContent[i] === '}') { + openBraces--; + } + + if (openBraces === 0) { + propsEnd = i; + break; + } + } + + const propsObjectString = fileContent.slice(propsStart, propsEnd + 1); + const propsObject = eval(`(${propsObjectString})`); + + return propsObject; +} + +/** + * Parses a JavaScript file content to extract custom events and their descriptions from JSDoc comments. + * + * @param {string} fileContent - The content of a JavaScript file as a string, expected to contain event declarations with JSDoc comments. + * @returns {Array} An array of event objects. + * + * This function creates an Abstract Syntax Tree (AST) from the file content and iterates through export declarations to locate event definitions. + * For each event with a literal type, the function extracts the name and associated JSDoc comment, cleans the comment, and stores both in the returned array. + */ +function parseContainerEvents(fileContent) { + if (!fileContent || fileContent === '') { + throw new Error('Cannot parse events in parseContainerEvents'); + } + const options = { + loc: true, + range: true, + tokens: true, + comment: true, + errorOnUnknownASTType: true + }; + + const ast = parse(fileContent, options); + + const events = []; + + ast.body.forEach((stmt) => { + if (stmt.type === 'ExportNamedDeclaration') { + stmt.declaration.body.body.forEach((eventName, index) => { + if (eventName.type === 'ExportNamedDeclaration') { + const { declaration } = eventName; + + if ( + declaration.type === 'VariableDeclaration' && + declaration.declarations[0].init && + declaration.declarations[0].init.type === 'Literal' + ) { + const name = declaration.declarations[0].init.value; + const jsdocComment = ast.comments[index].value.trim(); + let cleanedComment = jsdocComment + .split('\n') + .map((line) => { + if (line.trim().startsWith('*')) { + return line.trim().slice(1).trim(); + } + return line.trim(); + }) + .join(' ') + .trim(); + + events.push({ + name, + description: cleanedComment || 'No description' + }); + } + } + }); + } + }); + // Keep it for debugging purpose + // const outputPath = path.join(__dirname, 'eventsAst.json'); + // fs.writeFile(outputPath, JSON.stringify(ast, null, 2), (writeErr) => { + // if (writeErr) { + // console.error('Error to write JSON-file:', writeErr); + // return; + // } + // console.log('Created file successfully!'); + // }); + return events; +} + +/** + * Generates an array of module objects based on the provided container definitions. + * + * @param {Array} containers - An array of container objects, each containing properties + * needed to generate a module structure. + * @returns {Array} An array of module objects. + */ +function generateModules(containers) { + if (!containers || !containers.length) { + throw new Error('Cannot create modules for cem in generateModules'); + } + const modules = []; + containers.forEach((container) => { + let module = { + kind: 'javascript-module', + path: container.modulePath, + declarations: [ + { + kind: 'class', + description: container.containerName, + name: container.containerName, + tagName: container.tagName, + customElement: true, + members: generateMembers(container.containerMembers, container.containerFields), + events: generateEvents(container.containerEvents) + } + ], + exports: [ + { + kind: 'js', + name: container.containerName, + declaration: { + name: container.containerName, + module: container.module + } + }, + { + kind: 'custom-element-definition', + name: container.tagName, + declaration: { + name: container.containerName, + module: container.module + } + } + ] + }; + modules.push(module); + }); + return modules; +} + +/** + * Generates the custom element manifest file + * @param {Array} containers meta data for luigi container and luigi compound container + * @returns a custom element manifest + */ +function generateCEM(containers) { + const modules = generateModules(containers); + if (!modules && !modules.length) { + throw new Error('Cannot create modules for cem in generateCEM.'); + } else { + return { + schemaVersion: '2.1.0', + readme: '', + modules + }; + } +} + +/** + * Generates an array of member objects based on provided properties and methods. + * + * @param {Object} props - An object representing properties of the members, where each key is a property name + * and each value is an object describing the property's type. + * @param {Array} methods - An array of method names for the members. + * + * @returns {Array} An array of member objects, where each object represents either a field or a method. + */ +function generateMembers(props, methods) { + if (!props || !methods) { + throw new Error('Props or methods in generateMembers are undefined'); + } + const members = []; + for (let key in props) { + let member = { + kind: 'field', + name: key, + type: generateMemberType(key, props[key]), + default: 'undefined' + }; + members.push(member); + } + methods.forEach((methodName) => { + members.push({ + kind: 'method', + name: methodName + }); + }); + return members; +} + +/** + * Generates a member type object based on the provided key and value. + * + * @param {string} key - The name of the member. + * @param {Object} value - An object representing the member's details, typically containing a `type` property. + * @param {string} value.type - The type of the member, which can be `Array`, `String`, `Object`, `Boolean`, or other types. + * + * @returns {Object} A member type object. + */ +function generateMemberType(key, value) { + if (!key || !value) { + throw new Error('Cannont create member object in generateMemberType'); + } + if (value.type === 'Array') { + return { + text: 'Array', + references: [ + { + name: 'string' + } + ] + }; + } else if (value.type === 'String' || value.type === 'Object' || value.type === 'Boolean') { + if (key === 'context' || key === 'webcomponent') { + return { text: 'any' }; + } else { + return { + text: String(value.type).toLowerCase() + }; + } + } else { + return { + text: value.type + }; + } +} + +/** + * Generates an array of event objects based on the provided `events` input. + * @param {Object} events - An object containing event definitions, where each key is an event name, + * and each value is an object with `name` and `description` properties. + * @param {string} events[].name - The name of the event. + * @param {string} events[].description - A description of the event. + * @returns {Array} An array of event objects. + */ +function generateEvents(events) { + if (!events || !events.length) { + throw new Error('No events in generateEvents'); + } + const eventsArray = []; + events.forEach((event) => { + let ev = { + name: event.name, + description: event.description, + type: { text: 'Event' } + }; + eventsArray.push(ev); + }); + return eventsArray; +} + +/** + * Parses a JavaScript file content and extracts method names from it. + * + * @param {string} fileContent - The content of the JavaScript file as a string, which should define one or more classes or objects. + * @returns {Array} An array of method names found within the file content. + * + * This function utilizes a parsed Abstract Syntax Tree (AST) from the file content to identify method definitions. + * It iterates through the AST and collects the names of all methods defined in class bodies. + */ +function parseContainerMethods(fileContent) { + if (!fileContent || fileContent === '') { + throw new Error('No fileContent in parseContainerMethods'); + } + const ast = parse(fileContent); + const methods = []; + + ast.body.forEach((stmt) => { + stmt.declaration.body.body.forEach((property) => { + if (property.type === 'MethodDefinition') { + methods.push(property.key.name); + } + }); + }); + + // Keep it for debugging purpose + // const fileName = ast.body[1].declaration.id.name; + // const outputPath = path.join(__dirname, fileName+'_typingsAst.json'); + // fs.writeFile(outputPath, JSON.stringify(ast, null, 2), (writeErr) => { + // if (writeErr) { + // console.error('Error to write JSON-file:', writeErr); + // return; + // } + // console.log('Created file successfully!'); + // }); + + return methods; +} + +/** + * Writes the custom element manifest to a file. + * @param {Object} cem custom element manifest file in json format + */ +function writeFile(cem) { + if (!cem || Object.keys(cem).length === 0) { + throw new Error('CEM is empty. Cannot write file.'); + } + const outputPath = path.join(__dirname, 'public/dist/custom-elements.json'); + fs.writeFile(outputPath, JSON.stringify(cem, null, 2), (writeErr) => { + if (writeErr) { + console.error('Error to write JSON-file:', writeErr); + return; + } + console.log('Created file successfully!'); + }); +} + +function main() { + const getFileContent = (filePath) => fs.readFileSync(path.join(__dirname, filePath), 'utf-8'); + try { + const luigiContainerFileContent = getFileContent(luigiContainerPath); + const luigiCompoundContainerFileContent = getFileContent(luigiCompoundContainerPath); + const luigiContainerTypingsContent = getFileContent(luigiContainerTypingsPath); + const luigiCompoundContainerTypingsContent = getFileContent(luigiCompoundContainerTypingsPath); + const eventsFileContent = getFileContent(luigiEventsPath); + + const events = parseContainerEvents(eventsFileContent); + const containersMetaData = [ + { + containerName: 'LuigiContainer', + module: 'LuigiContainer.js', + tagName: 'luigi-container', + modulePath: 'dist/bundle.js', + containerMembers: parseContainerProps(luigiContainerFileContent), + containerEvents: events, + containerFields: parseContainerMethods(luigiContainerTypingsContent) + }, + { + containerName: 'LuigiCompoundContainer', + module: 'LuigiCompoundContainer.js', + tagName: 'luigi-compound-container', + modulePath: 'dist/bundle.js', + containerMembers: parseContainerProps(luigiCompoundContainerFileContent), + containerEvents: events, + containerFields: parseContainerMethods(luigiCompoundContainerTypingsContent) + } + ]; + + const cem = generateCEM(containersMetaData); + + writeFile(cem); + } catch (error) { + console.error('Error: ', error.message); + } +} + +main(); diff --git a/container/package-lock.json b/container/package-lock.json index 15d5c9bf19..8b4ab37b26 100644 --- a/container/package-lock.json +++ b/container/package-lock.json @@ -20,6 +20,7 @@ "@types/jest": "^29.5.12", "@typescript-eslint/eslint-plugin": "^8.13.0", "@typescript-eslint/parser": "^8.13.0", + "@typescript-eslint/typescript-estree": "^8.13.0", "chokidar-cli": "^3.0.0", "cli-color": "^2.0.4", "concurrently": "^7.6.0", @@ -1934,6 +1935,19 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { "version": "4.12.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", @@ -2856,19 +2870,6 @@ "eslint": ">=8.40.0" } }, - "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -3313,6 +3314,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -4124,9 +4138,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001677", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", - "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", + "version": "1.0.30001678", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001678.tgz", + "integrity": "sha512-RR+4U/05gNtps58PEBDZcPWTgEO2MBeoPZ96aQcjmfkBWRIDfN451fW2qyDA9/+HohLLIL5GqiMwA+IB1pWarw==", "dev": true, "funding": [ { @@ -4739,9 +4753,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", "dev": true, "license": "MIT", "dependencies": { @@ -5665,13 +5679,13 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5688,19 +5702,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -5761,19 +5762,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -11034,6 +11022,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/svelte-eslint-parser/node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", diff --git a/container/package.json b/container/package.json index 6994e50a21..6f1fdfee1a 100644 --- a/container/package.json +++ b/container/package.json @@ -12,7 +12,7 @@ "public" ], "scripts": { - "build": "npm run sync-event-typings && rollup -c", + "build": "npm run sync-event-typings && npm run generate-cem && rollup -c", "test": "jest", "lint": "eslint src/**/*.*", "bundle": "npm run build", @@ -29,7 +29,9 @@ "cypress-browser": "cypress open --e2e --browser chrome -c video=false", "release": "node release-cli.js", "replace-version-in-docu": "node prepareNextRelease.js", - "sync-event-typings": "cp src/constants/communication.ts typings/constants/events.d.ts" + "sync-event-typings": "cp src/constants/communication.ts typings/constants/events.d.ts", + "generate-cem": "node generateCEM.js" + }, "devDependencies": { "@babel/node": "7.22.10", @@ -63,6 +65,7 @@ "svelte-preprocess": "5.0.4", "tslib": "2.6.1", "typescript": "5.1.6", + "@typescript-eslint/typescript-estree": "^8.13.0", "typescript-eslint": "^8.13.0" }, "engines": { diff --git a/container/public/LuigiCompoundContainer.js b/container/public/LuigiCompoundContainer.js index 35e5f15204..b5452a7715 100644 --- a/container/public/LuigiCompoundContainer.js +++ b/container/public/LuigiCompoundContainer.js @@ -1 +1 @@ -export { LuigiCompoundContainer as default } from "./bundle.js"; \ No newline at end of file +export { LuigiCompoundContainer as default } from './bundle.js'; diff --git a/container/public/LuigiContainer.js b/container/public/LuigiContainer.js index b9ee6e194f..a696559eb6 100644 --- a/container/public/LuigiContainer.js +++ b/container/public/LuigiContainer.js @@ -1 +1 @@ -export { LuigiContainer as default } from "./bundle.js"; \ No newline at end of file +export { LuigiContainer as default } from './bundle.js'; diff --git a/container/public/dist/custom-elements.json b/container/public/dist/custom-elements.json index 41f582f27e..c2c2927285 100644 --- a/container/public/dist/custom-elements.json +++ b/container/public/dist/custom-elements.json @@ -209,15 +209,8 @@ "name": "webcomponent", "type": { "text": "any" - } - }, - { - "kind": "method", - "name": "closeAlert" - }, - { - "kind": "method", - "name": "sendCustomMessage" + }, + "default": "undefined" }, { "kind": "method", @@ -225,11 +218,11 @@ }, { "kind": "method", - "name": "attributeChangedCallback" + "name": "sendCustomMessage" }, { "kind": "method", - "name": "getNoShadow" + "name": "closeAlert" }, { "kind": "method", @@ -239,224 +232,224 @@ "events": [ { "name": "custom-message", - "description": "A message emitted from the micro frontend when a custom message is sent.", + "description": "Event fired when the micro frontend sends a custom message.", "type": { "text": "Event" } }, { "name": "get-context-request", - "description": "A message emitted from the micro frontend when the context data is sent.", + "description": "Event fired when the micro frontend requests the context data.", "type": { "text": "Event" } }, { "name": "navigation-request", - "description": "A message emitted from the micro frontend when a navigation request is sent.", + "description": "Event fired when a navigation has been requested by the micro frontend.", "type": { "text": "Event" } }, { "name": "show-alert-request", - "description": "A message emitted from the micro frontend when a request to show an alert is sent.", + "description": "Event fired when the micro frontend requests to show an alert.", "type": { "text": "Event" } }, { "name": "close-alert-request", - "description": "A message emitted from the micro frontend when a request to close an alert is sent.", + "description": "Event fired when the micro frontend requests to close an alert.", "type": { "text": "Event" } }, { "name": "initialized", - "description": "A message emitted from the micro frontend when it is first initialized.", + "description": "Event fired when the micro frontend has been initialized.", "type": { "text": "Event" } }, { "name": "add-search-params-request", - "description": "A message emitted from the micro frontend to request adding search parameters to the URL.", + "description": "Event fired when the micro frontend requests the addition of search parameters to the URL.", "type": { "text": "Event" } }, { "name": "add-node-params-request", - "description": "A message emitted from the micro frontend to request adding node parameters to the URL.", + "description": "Event fired when the micro frontend requests the addition of node parameters to the URL.", "type": { "text": "Event" } }, { "name": "show-confirmation-modal-request", - "description": "A message emitted from the micro frontend when a request to show a confirmation modal is sent.", + "description": "Event fired when the micro frontend requests to show a confirmation modal.", "type": { "text": "Event" } }, { "name": "show-loading-indicator-request", - "description": "A message emitted from the micro frontend when a request to show a loading indicator is sent.", + "description": "Event fired when the micro frontend requests to show a loading indicator.", "type": { "text": "Event" } }, { "name": "hide-loading-indicator-request", - "description": "A message emitted from the micro frontend when a request to hide the loading indicator is sent.", + "description": "Event fired when the micro frontend requests to hide the loading indicator.", "type": { "text": "Event" } }, { "name": "set-current-locale-request", - "description": "A message emitted from the micro frontend when a request to set the current locale is sent.", + "description": "Event fired when the micro frontend requests to set the current locale.", "type": { "text": "Event" } }, { "name": "set-storage-request", - "description": "A message emitted from the micro frontend when a request to modify the local storage is sent.", + "description": "Event fired when the micro frontend requests to modify the local storage.", "type": { "text": "Event" } }, { "name": "runtime-error-handling-request", - "description": "A message emitted from the micro frontend when a request to handle an error during runtime is sent.", + "description": "Event fired when the micro frontend requests to handle errors that might happen during the runtime of the micro frontend.", "type": { "text": "Event" } }, { "name": "set-anchor-request", - "description": "A message emitted from the micro frontend when a request to set the anchor of the URL is sent.", + "description": "Event fired when the micro frontend requests to set the anchor of the URL.", "type": { "text": "Event" } }, { "name": "set-third-party-cookies-request", - "description": "A message emitted from the micro frontend when a request to set third-party cookies is sent.", + "description": "Event fired when the micro frontend requests to set third-party cookies.", "type": { "text": "Event" } }, { "name": "navigate-back-request", - "description": "A message emitted from the micro frontend when a request to navigate back is sent.", + "description": "Event fired when the micro frontend requests to navigate back.", "type": { "text": "Event" } }, { "name": "get-current-route-request", - "description": "A message emitted from the micro frontend when a request to receive the current app route is sent.", + "description": "Event fired when the micro frontend requests the current app route.", "type": { "text": "Event" } }, { "name": "report-navigation-completed-request", - "description": "A message emitted from the micro frontend to report that the navigation is completed.", + "description": "Event fired to report that the micro frontend's navigation has completed.", "type": { "text": "Event" } }, { "name": "update-modal-path-data-request", - "description": "A message emitted from the micro frontend when a request to update the modal path parameters is sent.", + "description": "Event fired when the micro frontend requests to update the modal path parameters.", "type": { "text": "Event" } }, { "name": "check-path-exists-request", - "description": "A message emitted from the micro frontend when a request to check the validity of a path is sent.", + "description": "Event fired when the micro frontend requests to check the validity of a path.", "type": { "text": "Event" } }, { "name": "set-dirty-status-request", - "description": "A message emitted from the micro frontend when a request to set the 'dirty status' is sent.", + "description": "Event fired when the micro frontend requests to set the 'dirty status' which, for example, avoids closing when there are any unsaved changes.", "type": { "text": "Event" } }, { "name": "set-viewgroup-data-request", - "description": "A message emitted from the micro frontend when a request to set the view group data is sent.", + "description": "Event fired when the micro frontend requests to set the view group data.", "type": { "text": "Event" } }, { "name": "set-document-title-request", - "description": "A message emitted from the micro frontend when a request to set the document title is sent.", + "description": "Event fired when the micro frontend requests to set the document title.", "type": { "text": "Event" } }, { "name": "open-user-settings-request", - "description": "A message emitted from the micro frontend when a request to open user settings is sent.", + "description": "Event fired when the micro frontend requests to open the user settings.", "type": { "text": "Event" } }, { "name": "close-user-settings-request", - "description": "A message emitted from the micro frontend when a request to close user settings is sent.", + "description": "Event fired when the micro frontend requests to close the user settings.", "type": { "text": "Event" } }, { "name": "collapse-leftnav-request", - "description": "A message emitted from the micro frontend when a request to collapse the left side navigation is sent.", + "description": "Event fired when the micro frontend requests to collapse left side navigation.", "type": { "text": "Event" } }, { "name": "update-top-navigation-request", - "description": "A message emitted from the micro frontend when a request to update the top navigation is sent.", + "description": "Event fired when the micro frontend requests to update the top navigation.", "type": { "text": "Event" } }, { "name": "path-exists-request", - "description": "A message emitted from the micro frontend when a request to check if a path exists is sent.", + "description": "Event fired when the micro frontend requests to check if the path exists.", "type": { "text": "Event" } }, { "name": "go-back-request", - "description": "A message emitted from the micro frontend when a request to navigate back is sent.", + "description": "Event fired when the micro frontend requests to navigate back.", "type": { "text": "Event" } }, { "name": "has-back-request", - "description": "A message emitted from the micro frontend to check if there is a back navigation option.", + "description": "Event fired when the micro frontend requests to check if there are any preserved views.", "type": { "text": "Event" } }, { "name": "remove-backdrop-request", - "description": "A message emitted from the micro frontend when a request to remove the backdrop is sent.", + "description": "Event fired when the micro frontend requests to remove the backdrop.", "type": { "text": "Event" } @@ -648,20 +641,13 @@ "name": "webcomponent", "type": { "text": "any" - } + }, + "default": "undefined" }, { "kind": "method", "name": "updateContext" }, - { - "kind": "method", - "name": "attributeChangedCallback" - }, - { - "kind": "method", - "name": "getNoShadow" - }, { "kind": "method", "name": "init" @@ -670,224 +656,224 @@ "events": [ { "name": "custom-message", - "description": "A message emitted from the micro frontend when a custom message is sent.", + "description": "Event fired when the micro frontend sends a custom message.", "type": { "text": "Event" } }, { "name": "get-context-request", - "description": "A message emitted from the micro frontend when the context data is sent.", + "description": "Event fired when the micro frontend requests the context data.", "type": { "text": "Event" } }, { "name": "navigation-request", - "description": "A message emitted from the micro frontend when a navigation request is sent.", + "description": "Event fired when a navigation has been requested by the micro frontend.", "type": { "text": "Event" } }, { "name": "show-alert-request", - "description": "A message emitted from the micro frontend when a request to show an alert is sent.", + "description": "Event fired when the micro frontend requests to show an alert.", "type": { "text": "Event" } }, { "name": "close-alert-request", - "description": "A message emitted from the micro frontend when a request to close an alert is sent.", + "description": "Event fired when the micro frontend requests to close an alert.", "type": { "text": "Event" } }, { "name": "initialized", - "description": "A message emitted from the micro frontend when it is first initialized.", + "description": "Event fired when the micro frontend has been initialized.", "type": { "text": "Event" } }, { "name": "add-search-params-request", - "description": "A message emitted from the micro frontend to request adding search parameters to the URL.", + "description": "Event fired when the micro frontend requests the addition of search parameters to the URL.", "type": { "text": "Event" } }, { "name": "add-node-params-request", - "description": "A message emitted from the micro frontend to request adding node parameters to the URL.", + "description": "Event fired when the micro frontend requests the addition of node parameters to the URL.", "type": { "text": "Event" } }, { "name": "show-confirmation-modal-request", - "description": "A message emitted from the micro frontend when a request to show a confirmation modal is sent.", + "description": "Event fired when the micro frontend requests to show a confirmation modal.", "type": { "text": "Event" } }, { "name": "show-loading-indicator-request", - "description": "A message emitted from the micro frontend when a request to show a loading indicator is sent.", + "description": "Event fired when the micro frontend requests to show a loading indicator.", "type": { "text": "Event" } }, { "name": "hide-loading-indicator-request", - "description": "A message emitted from the micro frontend when a request to hide the loading indicator is sent.", + "description": "Event fired when the micro frontend requests to hide the loading indicator.", "type": { "text": "Event" } }, { "name": "set-current-locale-request", - "description": "A message emitted from the micro frontend when a request to set the current locale is sent.", + "description": "Event fired when the micro frontend requests to set the current locale.", "type": { "text": "Event" } }, { "name": "set-storage-request", - "description": "A message emitted from the micro frontend when a request to modify the local storage is sent.", + "description": "Event fired when the micro frontend requests to modify the local storage.", "type": { "text": "Event" } }, { "name": "runtime-error-handling-request", - "description": "A message emitted from the micro frontend when a request to handle an error during runtime is sent.", + "description": "Event fired when the micro frontend requests to handle errors that might happen during the runtime of the micro frontend.", "type": { "text": "Event" } }, { "name": "set-anchor-request", - "description": "A message emitted from the micro frontend when a request to set the anchor of the URL is sent.", + "description": "Event fired when the micro frontend requests to set the anchor of the URL.", "type": { "text": "Event" } }, { "name": "set-third-party-cookies-request", - "description": "A message emitted from the micro frontend when a request to set third-party cookies is sent.", + "description": "Event fired when the micro frontend requests to set third-party cookies.", "type": { "text": "Event" } }, { "name": "navigate-back-request", - "description": "A message emitted from the micro frontend when a request to navigate back is sent.", + "description": "Event fired when the micro frontend requests to navigate back.", "type": { "text": "Event" } }, { "name": "get-current-route-request", - "description": "A message emitted from the micro frontend when a request to receive the current app route is sent.", + "description": "Event fired when the micro frontend requests the current app route.", "type": { "text": "Event" } }, { "name": "report-navigation-completed-request", - "description": "A message emitted from the micro frontend to report that the navigation is completed.", + "description": "Event fired to report that the micro frontend's navigation has completed.", "type": { "text": "Event" } }, { "name": "update-modal-path-data-request", - "description": "A message emitted from the micro frontend when a request to update the modal path parameters is sent.", + "description": "Event fired when the micro frontend requests to update the modal path parameters.", "type": { "text": "Event" } }, { "name": "check-path-exists-request", - "description": "A message emitted from the micro frontend when a request to check the validity of a path is sent.", + "description": "Event fired when the micro frontend requests to check the validity of a path.", "type": { "text": "Event" } }, { "name": "set-dirty-status-request", - "description": "A message emitted from the micro frontend when a request to set the 'dirty status' is sent.", + "description": "Event fired when the micro frontend requests to set the 'dirty status' which, for example, avoids closing when there are any unsaved changes.", "type": { "text": "Event" } }, { "name": "set-viewgroup-data-request", - "description": "A message emitted from the micro frontend when a request to set the view group data is sent.", + "description": "Event fired when the micro frontend requests to set the view group data.", "type": { "text": "Event" } }, { "name": "set-document-title-request", - "description": "A message emitted from the micro frontend when a request to set the document title is sent.", + "description": "Event fired when the micro frontend requests to set the document title.", "type": { "text": "Event" } }, { "name": "open-user-settings-request", - "description": "A message emitted from the micro frontend when a request to open user settings is sent.", + "description": "Event fired when the micro frontend requests to open the user settings.", "type": { "text": "Event" } }, { "name": "close-user-settings-request", - "description": "A message emitted from the micro frontend when a request to close user settings is sent.", + "description": "Event fired when the micro frontend requests to close the user settings.", "type": { "text": "Event" } }, { "name": "collapse-leftnav-request", - "description": "A message emitted from the micro frontend when a request to collapse the left side navigation is sent.", + "description": "Event fired when the micro frontend requests to collapse left side navigation.", "type": { "text": "Event" } }, { "name": "update-top-navigation-request", - "description": "A message emitted from the micro frontend when a request to update the top navigation is sent.", + "description": "Event fired when the micro frontend requests to update the top navigation.", "type": { "text": "Event" } }, { "name": "path-exists-request", - "description": "A message emitted from the micro frontend when a request to check if a path exists is sent.", + "description": "Event fired when the micro frontend requests to check if the path exists.", "type": { "text": "Event" } }, { "name": "go-back-request", - "description": "A message emitted from the micro frontend when a request to navigate back is sent.", + "description": "Event fired when the micro frontend requests to navigate back.", "type": { "text": "Event" } }, { "name": "has-back-request", - "description": "A message emitted from the micro frontend to check if there is a back navigation option.", + "description": "Event fired when the micro frontend requests to check if there are any preserved views.", "type": { "text": "Event" } }, { "name": "remove-backdrop-request", - "description": "A message emitted from the micro frontend when a request to remove the backdrop is sent.", + "description": "Event fired when the micro frontend requests to remove the backdrop.", "type": { "text": "Event" } diff --git a/container/src/LuigiCompoundContainer.svelte b/container/src/LuigiCompoundContainer.svelte index 5ce2c9afdf..9a6fe53660 100644 --- a/container/src/LuigiCompoundContainer.svelte +++ b/container/src/LuigiCompoundContainer.svelte @@ -36,7 +36,8 @@ reflect: false, attribute: 'user-settings' }, - viewurl: { type: 'String', reflect: false, attribute: 'viewurl' } + viewurl: { type: 'String', reflect: false, attribute: 'viewurl' }, + webcomponent: { type: 'String', reflect: false, attribute: 'webcomponent' } }, extend: (customElementConstructor) => { let notInitFn = (name) => { diff --git a/container/test-app/compound/helloWorldWC.js b/container/test-app/compound/helloWorldWC.js index 59271f5b07..6ad9fafe68 100644 --- a/container/test-app/compound/helloWorldWC.js +++ b/container/test-app/compound/helloWorldWC.js @@ -299,21 +299,11 @@ export default class extends HTMLElement { const path = 'hello-world-wc'; const ctx = { ctx: 123 }; - this.LuigiClient.linkManager() - .fromContext(ctx) - .navigate(); - this.LuigiClient.linkManager() - .fromClosestContext() - .navigate(path); - this.LuigiClient.linkManager() - .fromVirtualTreeRoot() - .navigate(path); - this.LuigiClient.linkManager() - .fromParent(ctx) - .navigate(path); - this.LuigiClient.linkManager() - .withParams('my-params') - .navigate(path); + this.LuigiClient.linkManager().fromContext(ctx).navigate(); + this.LuigiClient.linkManager().fromClosestContext().navigate(path); + this.LuigiClient.linkManager().fromVirtualTreeRoot().navigate(path); + this.LuigiClient.linkManager().fromParent(ctx).navigate(path); + this.LuigiClient.linkManager().withParams('my-params').navigate(path); this.LuigiClient.linkManager().navigate(path); this.LuigiClient.uxManager().showAlert({ text: 'LuigiClient.linkManager().navigate()', @@ -324,7 +314,7 @@ export default class extends HTMLElement { this.$openAsModalBtn = this._shadowRoot.querySelector('#openAsModalBtn'); this.$openAsModalBtn.addEventListener('click', () => { this.LuigiClient.linkManager().openAsModal('openAsModal-wc', { - title:'Modal Title', + title: 'Modal Title', size: 'm' }); }); @@ -346,7 +336,7 @@ export default class extends HTMLElement { this.LuigiClient.linkManager().updateTopNavigation(); this.LuigiClient.linkManager() .pathExists() - .then(result => { + .then((result) => { console.log('PATH EXISTS'); this.LuigiClient.uxManager().showAlert({ text: diff --git a/container/test-app/iframe/iframe-cookies.html b/container/test-app/iframe/iframe-cookies.html index 27a7d05bc1..0cacfa4c07 100644 --- a/container/test-app/iframe/iframe-cookies.html +++ b/container/test-app/iframe/iframe-cookies.html @@ -6,10 +6,11 @@

- This page is used to test **skip-cookie-check** feature for iFrame based LuigiContainer + This page is used to test **skip-cookie-check** feature for iFrame based + LuigiContainer

-
+
import Events from '../bundle.js'; const luigiContainer = document.querySelector( - '[data-test-id="iframe-based-container-test"]' + '[data-test-id="iframe-based-container-test"]', ); // SET_THIRD_PARTY_COOKIES_REQUEST - called on microfrontend startup - luigiContainer.addEventListener(Events.SET_THIRD_PARTY_COOKIES_REQUEST, event => { + luigiContainer.addEventListener(Events.SET_THIRD_PARTY_COOKIES_REQUEST, (event) => { console.log(Events.SET_THIRD_PARTY_COOKIES_REQUEST, event); alert( Events.SET_THIRD_PARTY_COOKIES_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data.data) + 'message received: ' + JSON.stringify(event.detail.data.data), ); }); diff --git a/container/test-app/iframe/iframe-settings.html b/container/test-app/iframe/iframe-settings.html index 9a5b804938..1ce5062df8 100644 --- a/container/test-app/iframe/iframe-settings.html +++ b/container/test-app/iframe/iframe-settings.html @@ -55,7 +55,7 @@

const deferInitContainer = document.getElementById('defer-init-test'); const deferInitButton = document.getElementById('defer-init-button'); - deferInitButton.addEventListener('click', function() { + deferInitButton.addEventListener('click', function () { deferInitContainer.init(); }); @@ -72,7 +72,7 @@

deferInitContainer.allowRules = [ 'microphone', "camera 'none'", - "geolocation 'self' https://a.example.com https://b.example.com" + "geolocation 'self' https://a.example.com https://b.example.com", ]; }); diff --git a/container/test-app/iframe/iframeContainer.html b/container/test-app/iframe/iframeContainer.html index acb1797d6d..99a8ef1b17 100644 --- a/container/test-app/iframe/iframeContainer.html +++ b/container/test-app/iframe/iframeContainer.html @@ -13,7 +13,7 @@

-
+
import Events from '../bundle.js'; const luigiContainer = document.querySelector( - '[data-test-id="iframe-based-container-test"]' + '[data-test-id="iframe-based-container-test"]', ); - luigiContainer.addEventListener(Events.NAVIGATION_REQUEST, event => { + luigiContainer.addEventListener(Events.NAVIGATION_REQUEST, (event) => { console.log(event.detail); window.location.hash = event.detail.link; if (confirm('Do you want to leave this page?')) { @@ -37,7 +37,7 @@

} }); - luigiContainer.addEventListener(Events.CUSTOM_MESSAGE, event => { + luigiContainer.addEventListener(Events.CUSTOM_MESSAGE, (event) => { alert('Custom message received: ' + JSON.stringify(event.detail)); }); @@ -49,7 +49,7 @@

// for testing send Custom message functionality sendCustomMessageBtn.addEventListener('click', () => { - luigiContainer.sendCustomMessage('update', {dataToSend: 'some data'}); + luigiContainer.sendCustomMessage('update', { dataToSend: 'some data' }); }); updateContextButton.addEventListener('click', () => { @@ -60,7 +60,7 @@

luigiContainer.setAttribute('auth-data', '{"accessToken": "updated token"}'); }); - const showAnAlert = alertSettings => { + const showAnAlert = (alertSettings) => { var popup = document.createElement('div'); var text = document.createTextNode(alertSettings.settings.text); popup.appendChild(text); @@ -70,7 +70,7 @@

dismissButton.addEventListener('click', () => { console.log( 'Dismiss clicked core side. Sending close message to mf of id =', - alertSettings.settings.id + alertSettings.settings.id, ); luigiContainer.closeAlert(alertSettings.settings.id, 'neverShowItAgain'); popup.style.display = 'none'; @@ -84,7 +84,7 @@

return dismissButton; }; - luigiContainer.addEventListener(Events.ALERT_REQUEST, event => { + luigiContainer.addEventListener(Events.ALERT_REQUEST, (event) => { console.log('params:', Events.ALERT_REQUEST, event); alert('show-alert-request message received: ' + JSON.stringify(event.detail)); console.log(event.detail.data.data); @@ -92,139 +92,139 @@

showAnAlert(alertSettings); }); - luigiContainer.addEventListener(Events.ADD_SEARCH_PARAMS_REQUEST, event => { + luigiContainer.addEventListener(Events.ADD_SEARCH_PARAMS_REQUEST, (event) => { console.log('params:', Events.ADD_SEARCH_PARAMS_REQUEST, event); alert( - 'add-search-params-request message received: ' + JSON.stringify(event.detail) + 'add-search-params-request message received: ' + JSON.stringify(event.detail), ); }); - luigiContainer.addEventListener(Events.ADD_NODE_PARAMS_REQUEST, event => { + luigiContainer.addEventListener(Events.ADD_NODE_PARAMS_REQUEST, (event) => { console.log(Events.ADD_NODE_PARAMS_REQUEST, event); alert( - 'add-node-params-request message received: ' + JSON.stringify(event.detail) + 'add-node-params-request message received: ' + JSON.stringify(event.detail), ); }); - luigiContainer.addEventListener(Events.SHOW_CONFIRMATION_MODAL_REQUEST, event => { + luigiContainer.addEventListener(Events.SHOW_CONFIRMATION_MODAL_REQUEST, (event) => { console.log(Events.SHOW_CONFIRMATION_MODAL_REQUEST, event); alert( - 'show-confirmation-modal message received: ' + JSON.stringify(event.detail) + 'show-confirmation-modal message received: ' + JSON.stringify(event.detail), ); }); - luigiContainer.addEventListener(Events.SHOW_LOADING_INDICATOR_REQUEST, event => { + luigiContainer.addEventListener(Events.SHOW_LOADING_INDICATOR_REQUEST, (event) => { console.log(Events.SHOW_LOADING_INDICATOR_REQUEST, event); alert( 'show-loading-indicator-request message received: ' + - JSON.stringify(event.detail.data) + JSON.stringify(event.detail.data), ); }); - luigiContainer.addEventListener(Events.HIDE_LOADING_INDICATOR_REQUEST, event => { + luigiContainer.addEventListener(Events.HIDE_LOADING_INDICATOR_REQUEST, (event) => { console.log(Events.HIDE_LOADING_INDICATOR_REQUEST, event); alert( 'hide-loading-indicator-request message received: ' + - JSON.stringify(event.detail.data) + JSON.stringify(event.detail.data), ); }); // SET_CURRENT_LOCALE_REQUEST - luigiContainer.addEventListener(Events.SET_CURRENT_LOCALE_REQUEST, event => { + luigiContainer.addEventListener(Events.SET_CURRENT_LOCALE_REQUEST, (event) => { console.log(Events.SET_CURRENT_LOCALE_REQUEST, event); alert( Events.SET_CURRENT_LOCALE_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // LOCAL_STORAGE_SET_REQUEST - luigiContainer.addEventListener(Events.LOCAL_STORAGE_SET_REQUEST, event => { + luigiContainer.addEventListener(Events.LOCAL_STORAGE_SET_REQUEST, (event) => { console.log(Events.LOCAL_STORAGE_SET_REQUEST, event); alert( Events.LOCAL_STORAGE_SET_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // RUNTIME_ERROR_HANDLING_REQUEST - luigiContainer.addEventListener(Events.RUNTIME_ERROR_HANDLING_REQUEST, event => { + luigiContainer.addEventListener(Events.RUNTIME_ERROR_HANDLING_REQUEST, (event) => { console.log(Events.RUNTIME_ERROR_HANDLING_REQUEST, event); alert( Events.RUNTIME_ERROR_HANDLING_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // SET_ANCHOR_LINK_REQUEST - luigiContainer.addEventListener(Events.SET_ANCHOR_LINK_REQUEST, event => { + luigiContainer.addEventListener(Events.SET_ANCHOR_LINK_REQUEST, (event) => { console.log(Events.SET_ANCHOR_LINK_REQUEST, event); alert( Events.SET_ANCHOR_LINK_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // SET_THIRD_PARTY_COOKIES_REQUEST - called on microfrontend startup - luigiContainer.addEventListener(Events.SET_THIRD_PARTY_COOKIES_REQUEST, event => { + luigiContainer.addEventListener(Events.SET_THIRD_PARTY_COOKIES_REQUEST, (event) => { console.log(Events.SET_THIRD_PARTY_COOKIES_REQUEST, event); alert( Events.SET_THIRD_PARTY_COOKIES_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data.data) + 'message received: ' + JSON.stringify(event.detail.data.data), ); }); // BACK_NAVIGATION_REQUEST - luigiContainer.addEventListener(Events.BACK_NAVIGATION_REQUEST, event => { + luigiContainer.addEventListener(Events.BACK_NAVIGATION_REQUEST, (event) => { console.log(Events.BACK_NAVIGATION_REQUEST, event); alert( Events.BACK_NAVIGATION_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // GET_CURRENT_ROUTE_REQUEST - luigiContainer.addEventListener(Events.GET_CURRENT_ROUTE_REQUEST, event => { + luigiContainer.addEventListener(Events.GET_CURRENT_ROUTE_REQUEST, (event) => { console.log(Events.GET_CURRENT_ROUTE_REQUEST, event); alert( Events.GET_CURRENT_ROUTE_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // NAVIGATION_COMPLETED_REPORT - luigiContainer.addEventListener(Events.NAVIGATION_COMPLETED_REPORT, event => { + luigiContainer.addEventListener(Events.NAVIGATION_COMPLETED_REPORT, (event) => { console.log(Events.NAVIGATION_COMPLETED_REPORT, event); alert( Events.NAVIGATION_COMPLETED_REPORT, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // UPDATE_MODAL_PATH_DATA_REQUEST - luigiContainer.addEventListener(Events.UPDATE_MODAL_PATH_DATA_REQUEST, event => { + luigiContainer.addEventListener(Events.UPDATE_MODAL_PATH_DATA_REQUEST, (event) => { console.log(Events.UPDATE_MODAL_PATH_DATA_REQUEST, event); alert( Events.UPDATE_MODAL_PATH_DATA_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // CHECK_PATH_EXISTS_REQUEST - luigiContainer.addEventListener(Events.CHECK_PATH_EXISTS_REQUEST, event => { + luigiContainer.addEventListener(Events.CHECK_PATH_EXISTS_REQUEST, (event) => { console.log(Events.CHECK_PATH_EXISTS_REQUEST, event); alert( Events.CHECK_PATH_EXISTS_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); // SET_DIRTY_STATUS_REQUEST - luigiContainer.addEventListener(Events.SET_DIRTY_STATUS_REQUEST, event => { + luigiContainer.addEventListener(Events.SET_DIRTY_STATUS_REQUEST, (event) => { console.log(Events.SET_DIRTY_STATUS_REQUEST, event); alert( Events.SET_DIRTY_STATUS_REQUEST, - 'message received: ' + JSON.stringify(event.detail.data) + 'message received: ' + JSON.stringify(event.detail.data), ); }); diff --git a/container/test-app/iframe/microfrontend-luigi-client-init.html b/container/test-app/iframe/microfrontend-luigi-client-init.html index dc66e55b08..ee01c659a5 100644 --- a/container/test-app/iframe/microfrontend-luigi-client-init.html +++ b/container/test-app/iframe/microfrontend-luigi-client-init.html @@ -1,7 +1,7 @@ - + - + Luigi Client Init Test @@ -16,19 +16,26 @@ const isInitialized = LuigiClient.isLuigiClientInitialized(); console.log('isInitialized: ' + isInitialized); if (document.getElementById('luigiClientStatus')) { - document.getElementById('luigiClientStatus').innerText = `Luigi Client Initialized: ${isInitialized}`; - + document.getElementById('luigiClientStatus').innerText = + `Luigi Client Initialized: ${isInitialized}`; } return isInitialized; } - - + +
-

Luigi Client Init Test for Iframes

- - -

Luigi Client Initialized: Unknown

+

Luigi Client Init Test for Iframes

+ + +

Luigi Client Initialized: Unknown

- + diff --git a/container/test-app/iframe/microfrontend.html b/container/test-app/iframe/microfrontend.html index b5cbf241e1..7a865ce525 100644 --- a/container/test-app/iframe/microfrontend.html +++ b/container/test-app/iframe/microfrontend.html @@ -1,5 +1,5 @@ - + @@ -32,7 +32,7 @@ - +

Multi purpose demo page

@@ -69,22 +69,22 @@

Multi purpose demo page

diff --git a/container/test-app/index.html b/container/test-app/index.html index 6982499a7d..afd1539ad5 100644 --- a/container/test-app/index.html +++ b/container/test-app/index.html @@ -1,4 +1,4 @@ - + diff --git a/container/test-app/wc/clientAPI.html b/container/test-app/wc/clientAPI.html index 68ca55a58e..cb5ef01a7c 100644 --- a/container/test-app/wc/clientAPI.html +++ b/container/test-app/wc/clientAPI.html @@ -14,7 +14,7 @@

sendCustomMessage -
+
import MFEventID from '../bundle.js'; const deferInitContainer = document.getElementById('defer-init-test'); const deferInitButton = document.getElementById('defer-init-button'); - deferInitButton.addEventListener('click', function() { + deferInitButton.addEventListener('click', function () { deferInitContainer.init(); }); // document.querySelector('luigi-container'); const container = document.querySelector( - '[data-test-id="luigi-client-api-test-01"]' + '[data-test-id="luigi-client-api-test-01"]', ); const sendCustomMsgBtn = document.getElementById('sendCustomMessageBtn'); sendCustomMsgBtn.addEventListener('click', () => { container.sendCustomMessage('custom-message-id', { - dataToSend: 'cool custom Message' + dataToSend: 'cool custom Message', }); }); - [...document.querySelectorAll('luigi-container')].forEach(luigiContainer => { - luigiContainer.addEventListener(MFEventID.NAVIGATION_REQUEST, event => { + [...document.querySelectorAll('luigi-container')].forEach((luigiContainer) => { + luigiContainer.addEventListener(MFEventID.NAVIGATION_REQUEST, (event) => { console.log(event.detail); window.location.hash = event.detail.link; }); - luigiContainer.addEventListener(MFEventID.ALERT_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.ALERT_REQUEST, (event) => { console.log(event.detail); alert(event.detail.text); }); luigiContainer.addEventListener( MFEventID.SHOW_CONFIRMATION_MODAL_REQUEST, - event => { + (event) => { const data = event.detail; console.log(data); const val = confirm(data.body); @@ -102,60 +102,63 @@

if (event.callback) { event.callback(val); } - } + }, ); - luigiContainer.addEventListener(MFEventID.CUSTOM_MESSAGE, event => { + luigiContainer.addEventListener(MFEventID.CUSTOM_MESSAGE, (event) => { if (event.detail.id !== 'timer') { alert(event.detail.data); } }); - luigiContainer.addEventListener(MFEventID.GO_BACK_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.GO_BACK_REQUEST, (event) => { console.log(event); }); luigiContainer.addEventListener( MFEventID.RUNTIME_ERROR_HANDLING_REQUEST, - event => { + (event) => { console.log(event.detail); - } + }, ); - luigiContainer.addEventListener(MFEventID.ADD_NODE_PARAMS_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.ADD_NODE_PARAMS_REQUEST, (event) => { const params = event.detail.params; console.log('params', params); }); - luigiContainer.addEventListener(MFEventID.SET_ANCHOR_LINK_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.SET_ANCHOR_LINK_REQUEST, (event) => { console.log('anchor', event.detail); }); - luigiContainer.addEventListener(MFEventID.OPEN_USER_SETTINGS_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.OPEN_USER_SETTINGS_REQUEST, (event) => { console.log('Open User Settings Request received', event.detail); alert('LuigiClient.uxManager().openUserSettings()'); }); - luigiContainer.addEventListener(MFEventID.CLOSE_USER_SETTINGS_REQUEST, event => { - console.log('Close User Settings Request received', event.detail); - alert('LuigiClient.uxManager().closeUserSettings()'); - }); - luigiContainer.addEventListener(MFEventID.REMOVE_BACKDROP_REQUEST, event => { + luigiContainer.addEventListener( + MFEventID.CLOSE_USER_SETTINGS_REQUEST, + (event) => { + console.log('Close User Settings Request received', event.detail); + alert('LuigiClient.uxManager().closeUserSettings()'); + }, + ); + luigiContainer.addEventListener(MFEventID.REMOVE_BACKDROP_REQUEST, (event) => { console.log('Remove Backdrop Request received', event.detail); alert('LuigiClient.uxManager().removeBackdrop()'); }); - luigiContainer.addEventListener(MFEventID.COLLAPSE_LEFT_NAV_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.COLLAPSE_LEFT_NAV_REQUEST, (event) => { console.log('Collapse Left Side Nav Request received', event.detail); alert('LuigiClient.uxManager().collapseLeftSideNav()'); }); - luigiContainer.addEventListener(MFEventID.SET_DOCUMENT_TITLE_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.SET_DOCUMENT_TITLE_REQUEST, (event) => { console.log('Set Document Title Request received', event.detail); luigiContainer.documentTitle = event.detail; }); luigiContainer.addEventListener( MFEventID.HIDE_LOADING_INDICATOR_REQUEST, - event => { + (event) => { console.log('Hide Loading Indicator Request received', event.detail); alert('LuigiClient.uxManager().hideAppLoadingIndicator()'); - } + }, ); // linkManager listeners: // path exists - luigiContainer.addEventListener(MFEventID.PATH_EXISTS_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.PATH_EXISTS_REQUEST, (event) => { console.log('Path Exists Request received', event.detail, event); // send back result with defined 'callback' // event: MFEventID.PathExistsEvent can be used as an event type to get the callback function @@ -163,11 +166,14 @@

}); // setViewGroup Data listener - luigiContainer.addEventListener(MFEventID.SET_VIEW_GROUP_DATA_REQUEST, event => { - console.log('Set View Group Data Request received', event.detail, event); - }); + luigiContainer.addEventListener( + MFEventID.SET_VIEW_GROUP_DATA_REQUEST, + (event) => { + console.log('Set View Group Data Request received', event.detail, event); + }, + ); - luigiContainer.addEventListener(MFEventID.GET_CURRENT_ROUTE_REQUEST, event => { + luigiContainer.addEventListener(MFEventID.GET_CURRENT_ROUTE_REQUEST, (event) => { event.callback(window.location.pathname); }); }); diff --git a/container/test-app/wc/helloWorldWC.js b/container/test-app/wc/helloWorldWC.js index b1972174ae..b3a401f019 100644 --- a/container/test-app/wc/helloWorldWC.js +++ b/container/test-app/wc/helloWorldWC.js @@ -135,7 +135,7 @@ export default class extends HTMLElement { this._shadowRoot.appendChild(openAsSplitviewBtn.content.cloneNode(true)); this._shadowRoot.appendChild(navigateBtn.content.cloneNode(true)); this._shadowRoot.appendChild(alertBtn.content.cloneNode(true)); - + this._shadowRoot.appendChild(linkManagerUpdateTopPathExistsBackBtn.content.cloneNode(true)); this._shadowRoot.appendChild(setViewGroupDataBtn.content.cloneNode(true)); this._shadowRoot.appendChild(getCurrentRouteBtn.content.cloneNode(true)); @@ -272,21 +272,11 @@ export default class extends HTMLElement { const path = 'hello-world-wc'; const ctx = { ctx: 123 }; - this.LuigiClient.linkManager() - .fromContext(ctx) - .navigate(); - this.LuigiClient.linkManager() - .fromClosestContext() - .navigate(path); - this.LuigiClient.linkManager() - .fromVirtualTreeRoot() - .navigate(path); - this.LuigiClient.linkManager() - .fromParent(ctx) - .navigate(path); - this.LuigiClient.linkManager() - .withParams('my-params') - .navigate(path); + this.LuigiClient.linkManager().fromContext(ctx).navigate(); + this.LuigiClient.linkManager().fromClosestContext().navigate(path); + this.LuigiClient.linkManager().fromVirtualTreeRoot().navigate(path); + this.LuigiClient.linkManager().fromParent(ctx).navigate(path); + this.LuigiClient.linkManager().withParams('my-params').navigate(path); this.LuigiClient.linkManager().navigate(path); this.LuigiClient.uxManager().showAlert({ text: 'LuigiClient.linkManager().navigate()', @@ -297,7 +287,7 @@ export default class extends HTMLElement { this.$openAsModalBtn = this._shadowRoot.querySelector('#openAsModalBtn'); this.$openAsModalBtn.addEventListener('click', () => { this.LuigiClient.linkManager().openAsModal('openAsModal-wc', { - title:'Modal Title', + title: 'Modal Title', size: 'm' }); }); @@ -317,18 +307,18 @@ export default class extends HTMLElement { this.$alertBtn = this._shadowRoot.querySelector('#alertBtn'); this.$alertBtn.addEventListener('click', () => { this.LuigiClient.uxManager().showAlert({ - text: "showAlert test", + text: 'showAlert test', type: 'info' }); - }) + }); this.$navigateBtn = this._shadowRoot.querySelector('#navigateBtn'); this.$navigateBtn.addEventListener('click', () => { - const path = "AAA.html"; + const path = 'AAA.html'; const modalSettings = { - title:'Modal Title', + title: 'Modal Title', size: 'm' - } + }; this.LuigiClient.linkManager().navigate(path, 0, true, modalSettings); }); @@ -337,7 +327,7 @@ export default class extends HTMLElement { this.LuigiClient.linkManager().updateTopNavigation(); this.LuigiClient.linkManager() .pathExists() - .then(result => { + .then((result) => { console.log('PATH EXISTS'); this.LuigiClient.uxManager().showAlert({ text: @@ -354,14 +344,14 @@ export default class extends HTMLElement { this.$goBackBtn = this._shadowRoot.querySelector('#goBackBtn'); this.$goBackBtn.addEventListener('click', () => { this.LuigiClient.linkManager().goBack(); - console.log("goBack() CLICKED"); + console.log('goBack() CLICKED'); }); this.$updateTopNavigationBtn = this._shadowRoot.querySelector('#updateTopNavigationBtn'); this.$updateTopNavigationBtn.addEventListener('click', () => { - console.log("updateTopNavigation() CLICKED 1"); + console.log('updateTopNavigation() CLICKED 1'); this.LuigiClient.linkManager().updateTopNavigationBtn(); - console.log("updateTopNavigation() CLICKED 2"); + console.log('updateTopNavigation() CLICKED 2'); }); this.$setViewGroupData = this._shadowRoot.querySelector('#setViewGroupData'); @@ -373,7 +363,7 @@ export default class extends HTMLElement { this.$getCurrentRoute.addEventListener('click', () => { this.LuigiClient.linkManager() .getCurrentRoute() - .then(result => { + .then((result) => { console.log(result); alert('current route: ' + result); }); @@ -387,7 +377,7 @@ export default class extends HTMLElement { } }); - this.addEventListener('custom-message-id', event => { + this.addEventListener('custom-message-id', (event) => { console.log('custom message received: ', event.detail); const customMessageDiv = this._shadowRoot.querySelector('#customMessageDiv'); customMessageDiv.textContent = `Received Custom Message: ${event.detail.dataToSend}`; diff --git a/container/test/services/container.service.spec.ts b/container/test/services/container.service.spec.ts index d18108c95c..3a922af00f 100644 --- a/container/test/services/container.service.spec.ts +++ b/container/test/services/container.service.spec.ts @@ -1,675 +1,675 @@ -import { LuigiInternalMessageID } from '../../src/constants/internal-communication'; -import { Events } from '../../src/constants/communication'; -import { ContainerService } from '../../src/services/container.service'; - -describe('getContainerManager messageListener', () => { - let service: ContainerService; - let gtcSpy; - let cw: any = {}; - let cm; - let dispatchedEvent; - service = new ContainerService(); - cm = service.getContainerManager(); - - beforeEach(() => { - // only get context scenario relies on postMessage, so we need special case handling for it - const testName = expect.getState().currentTestName; - if (testName === 'test get context message') { - cw = { postMessage: () => {} }; - } - - gtcSpy = jest.spyOn(service, 'getTargetContainer').mockImplementation(() => { - return { - iframeHandle: { - iframe: { - contentWindow: cw - } - }, - dispatchEvent: customEvent => { - dispatchedEvent = customEvent; - } - }; - }); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('test alert request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.ALERT_REQUEST, - data: { - id: 'navRequest' - } - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.ALERT_REQUEST); - expect(dispatchedEvent.detail).toEqual({ - data: { data: { id: 'navRequest' }, msg: 'luigi.ux.alert.show' }, - source: {} - }); - }); - - it('test custom message', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.CUSTOM_MESSAGE, - data: { - id: 'custMsgId', - foo: 'bar' - } - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.CUSTOM_MESSAGE); - expect(dispatchedEvent.detail).toEqual({ id: 'custMsgId', _metaData: {}, data: { foo: 'bar' } }); - gtcSpy.mockRestore(); - }); - - it('test get context message', () => { - const event = { - origin: '*', - source: cw, - data: { - msg: LuigiInternalMessageID.GET_CONTEXT, - data: { - id: 'custMsgId', - foo: 'bar' - } - } - }; - - // Create a mock for the postMessage method - const postMessageMock = jest.fn(); - - // Replace the real postMessage with the mock - cw.postMessage = postMessageMock; - - // Define the message to send and target Origin - const message = { - authData: {}, - context: {}, - internal: { - thirdPartyCookieCheck: { - disabled: false - } - }, - msg: 'luigi.init' - }; - const targetOrigin = '*'; - - // Call the method that should trigger postMessage - cm.messageListener(event); - - // Assert that postMessage was called with the expected parameters - expect(postMessageMock).toHaveBeenCalledWith(message, targetOrigin); - - // Clean up by restoring the original postMessage function - cw.postMessage = () => {}; - cw.origin = undefined; - }); - - it('test initialized request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.INITIALIZED, - params: 'init' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.INITIALIZED); - expect(dispatchedEvent.detail).toEqual('init'); - }); - - it('test add search params request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.ADD_SEARCH_PARAMS_REQUEST, - keepBrowserHistory: true, - data: 'some-data' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.ADD_SEARCH_PARAMS_REQUEST); - expect(dispatchedEvent.detail).toEqual({ data: 'some-data', keepBrowserHistory: true }); - }); - - it('test add node params request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.ADD_NODE_PARAMS_REQUEST, - keepBrowserHistory: false, - data: 'some-data' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.ADD_NODE_PARAMS_REQUEST); - expect(dispatchedEvent.detail).toEqual({ data: 'some-data', keepBrowserHistory: false }); - }); - - it('test confirmationModal show request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.SHOW_CONFIRMATION_MODAL_REQUEST, - params: 'modal-show' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.SHOW_CONFIRMATION_MODAL_REQUEST); - }); - - it('test loading indicator show request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.SHOW_LOADING_INDICATOR_REQUEST, - params: 'loading-indicator-show' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.SHOW_LOADING_INDICATOR_REQUEST); - }); - - it('test loading indicator hide request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.HIDE_LOADING_INDICATOR_REQUEST, - params: 'loading-indicator-hide' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.HIDE_LOADING_INDICATOR_REQUEST); - }); - - it('test set locale request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.SET_CURRENT_LOCALE_REQUEST, - params: 'set-locale' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.SET_CURRENT_LOCALE_REQUEST); - }); - - it('test set local storage request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.LOCAL_STORAGE_SET_REQUEST, - params: 'set-local-storage' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.LOCAL_STORAGE_SET_REQUEST); - }); - - it('test runtime error handling request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.RUNTIME_ERROR_HANDLING_REQUEST, - params: 'set-runtime-error-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.RUNTIME_ERROR_HANDLING_REQUEST); - }); - - it('test anchor link request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.SET_ANCHOR_LINK_REQUEST, - params: 'set-anchor-link-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.SET_ANCHOR_LINK_REQUEST); - }); - - it('test third party cookies request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.SET_THIRD_PARTY_COOKIES_REQUEST, - params: 'set-thirdparty-cookies-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.SET_THIRD_PARTY_COOKIES_REQUEST); - }); - - it('test navigation back request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.BACK_NAVIGATION_REQUEST, - params: 'back-navigation-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.BACK_NAVIGATION_REQUEST); - }); - - it('test navigation request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.NAVIGATION_REQUEST, - params: 'navigation-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.NAVIGATION_REQUEST); - }); - - it('test getCurrentRoute request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.GET_CURRENT_ROUTE_REQUEST, - params: 'get-currentroute-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.GET_CURRENT_ROUTE_REQUEST); - }); - - it('test getCurrentRoute request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.GET_CURRENT_ROUTE_REQUEST, - params: 'get-currentroute-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.GET_CURRENT_ROUTE_REQUEST); - }); - - it('test navigation completed request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.NAVIGATION_COMPLETED_REPORT, - params: 'nav-completed-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.NAVIGATION_COMPLETED_REPORT); - }); - - it('test update modalPath data request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.UPDATE_MODAL_PATH_DATA_REQUEST, - params: 'update-modalpathdata-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.UPDATE_MODAL_PATH_DATA_REQUEST); - }); - - it('test check pathExists request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.CHECK_PATH_EXISTS_REQUEST, - params: 'update-check-pathexists-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.CHECK_PATH_EXISTS_REQUEST); - }); - - it('test set dirty status request', () => { - const event = { - source: cw, - data: { - msg: LuigiInternalMessageID.SET_DIRTY_STATUS_REQUEST, - params: 'set-dirtystatus-request' - } - }; - cm.messageListener(event); - expect(dispatchedEvent.type).toEqual(Events.SET_DIRTY_STATUS_REQUEST); - }); - - it('test default', () => { - const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(jest.fn()); - const event = { - source: cw, - data: { - msg: 'no-func' - } - }; - cm.messageListener(event); - expect(consoleWarnSpy).not.toHaveBeenCalled(); - }); -}); - -describe('isVisible', () => { - let service: ContainerService; - service = new ContainerService(); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should return true for a visible element', () => { - // Arrange - const visibleElement = document.createElement('div'); - jest.spyOn(visibleElement, 'offsetWidth', 'get').mockImplementation(() => 200); - document.body.appendChild(visibleElement); - - // Act - const result = service.isVisible(visibleElement); - - // Assert - expect(result).toBe(true); - }); - - it('should return false for a hidden element', () => { - // Arrange - const hiddenElement = document.createElement('div'); - hiddenElement.style.display = 'none'; - document.body.appendChild(hiddenElement); - - // Act - const result = service.isVisible(hiddenElement); - - // Assert - expect(result).toBe(false); - }); - - it('should return false for an element with zero dimensions', () => { - // Arrange - const zeroSizeElement = document.createElement('div'); - zeroSizeElement.style.width = '0'; - zeroSizeElement.style.height = '0'; - document.body.appendChild(zeroSizeElement); - - // Act - const result = service.isVisible(zeroSizeElement); - - // Assert - expect(result).toBe(false); - }); -}); - -describe('sendCustomMessageToIframe', () => { - let service: ContainerService; - service = new ContainerService(); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should send a custom message to the iframe', () => { - // Arrange - const iframeHandle = { - iframe: { - contentWindow: { - postMessage: jest.fn() - }, - src: 'https://example.com' - } - }; - const message = { key: 'value' }; - - // Act - service.sendCustomMessageToIframe(iframeHandle, message); - - // Assert - expect(iframeHandle.iframe.contentWindow.postMessage).toHaveBeenCalledWith( - { msg: 'custom', data: message }, - 'https://example.com' - ); - }); - - it('should send a named message to the iframe', () => { - // Arrange - const iframeHandle = { - iframe: { - contentWindow: { - postMessage: jest.fn() - }, - src: 'https://example.com' - } - }; - const message = { key: 'value' }; - - // Act - service.sendCustomMessageToIframe(iframeHandle, message, 'namedMessage'); - - // Assert - expect(iframeHandle.iframe.contentWindow.postMessage).toHaveBeenCalledWith( - { msg: 'namedMessage', key: 'value' }, - 'https://example.com' - ); - }); - - it('should log an error if contentWindow is not available', () => { - // Arrange - const iframeHandle = { - iframe: {} - }; - const message = { key: 'value' }; - - // Spy on console.error to capture the log message - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); - - // Act - service.sendCustomMessageToIframe(iframeHandle, message); - - // Assert - expect(consoleErrorSpy).toHaveBeenCalledWith('Message target could not be resolved'); - - // Restore the original console.error function - consoleErrorSpy.mockRestore(); - }); -}); - -describe('dispatch', () => { - let service: ContainerService; - service = new ContainerService(); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should dispatch a custom event to the target container, no Callback', () => { - // Arrange - const targetContainer = document.createElement('div'); - const eventName = 'customEvent'; - const eventData = { key: 'value' }; - targetContainer.dispatchEvent = jest.fn(); - - // Act - service.dispatch(eventName, targetContainer, eventData); - - // Assert - const dispatchedEvent = new CustomEvent(eventName, { detail: eventData }); - expect(targetContainer.dispatchEvent).toHaveBeenCalledWith(dispatchedEvent); - }); - - it('should execute the callback when provided', () => { - // Arrange - const targetContainer = document.createElement('div'); - const eventName = 'customEvent'; - const eventData = { key: 'value' }; - targetContainer.dispatchEvent = jest.fn(); - - // Define a callback function - const callbackFunction = data => { - // This function should not be called in this test - }; - - // Act - service.dispatch(eventName, targetContainer, eventData, callbackFunction, 'onCallback'); - - // Assert - globalThis.CustomEvent = jest - .fn() - .mockImplementation((type, eventInit) => ({ isTrusted: false, onCallback: callbackFunction })); - - const dispatchedEventMock = { isTrusted: false, onCallback: expect.any(Function) }; - expect(targetContainer.dispatchEvent).toHaveBeenCalledWith(expect.objectContaining(dispatchedEventMock)); - }); -}); - -describe('getTargetContainer', () => { - let service: ContainerService; - service = new ContainerService(); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should return the correct container when a matching container is found', () => { - // Arrange - const mockContainer1 = { - iframeHandle: { - iframe: { - contentWindow: 'source1' - } - } - }; - const mockContainer2 = { - iframeHandle: { - iframe: { - contentWindow: 'source2' - } - } - }; - - globalThis.__luigi_container_manager = { - container: [mockContainer1, mockContainer2] - }; - - const mockEvent = { - source: 'source2' // Matched with mockContainer2 - }; - - // Act - const targetContainer = service.getTargetContainer(mockEvent); - - // Assert - expect(targetContainer).toBe(mockContainer2); - }); - - it('should return undefined when no matching container is found', () => { - // Arrange - const mockContainer1 = { - iframeHandle: { - iframe: { - contentWindow: 'source1' - } - } - }; - const mockContainer2 = { - iframeHandle: { - iframe: { - contentWindow: 'source2' - } - } - }; - - globalThis.__luigi_container_manager = { - container: [mockContainer1, mockContainer2] - }; - - const mockEvent = { - source: 'source3' // No matching container - }; - - // Act - const targetContainer = service.getTargetContainer(mockEvent); - - // Assert - expect(targetContainer).toBe(undefined); - }); -}); - -describe('getContainerManager branch', () => { - let service: ContainerService; - service = new ContainerService(); - - beforeEach(() => { - globalThis.__luigi_container_manager = undefined; - jest.resetAllMocks(); - }); - - afterEach(() => { - // Reset the global state after each test - globalThis.__luigi_container_manager = undefined; - window.removeEventListener('message', globalThis.__luigi_container_manager?.messageListener); - }); - - it('should initialize and return the container manager', () => { - const containerManager = service.getContainerManager(); - expect(containerManager).toBeDefined(); - expect(containerManager.container).toEqual([]); - expect(containerManager.messageListener).toBeDefined(); - }); - - it('should return the existing container manager if it has been initialized', () => { - const existingManager = { - container: ['existingData'], - messageListener: jest.fn() - }; - globalThis.__luigi_container_manager = existingManager; - - const containerManager = service.getContainerManager(); - expect(containerManager).toBe(existingManager); - }); - - it('should add a message event listener when initializing', () => { - globalThis.__luigi_container_manager = undefined; - const spy = jest.spyOn(window, 'addEventListener'); - - const containerManager = service.getContainerManager(); // Initialize the manager - - // Verify that addEventListener was called with 'message' event type - expect(containerManager).toBeDefined(); - expect(containerManager.container).toEqual([]); - expect(spy).toHaveBeenCalledWith('message', expect.any(Function)); - }); -}); - -describe('registerContainer', () => { - let service: ContainerService; - service = new ContainerService(); - - beforeEach(() => { - jest.resetAllMocks(); - }); - - it('should add an HTMLElement to the container', () => { - // Arrange - const containerManager = { - container: [] - }; - const container = document.createElement('div'); - service.getContainerManager = jest.fn().mockReturnValue(containerManager); - - // Act - service.registerContainer(container); - - // Assert - expect(containerManager.container).toContain(container); - expect(service.getContainerManager).toHaveBeenCalled(); - }); -}); +import { LuigiInternalMessageID } from '../../src/constants/internal-communication'; +import { Events } from '../../src/constants/communication'; +import { ContainerService } from '../../src/services/container.service'; + +describe('getContainerManager messageListener', () => { + let service: ContainerService; + let gtcSpy; + let cw: any = {}; + let cm; + let dispatchedEvent; + service = new ContainerService(); + cm = service.getContainerManager(); + + beforeEach(() => { + // only get context scenario relies on postMessage, so we need special case handling for it + const testName = expect.getState().currentTestName; + if (testName === 'test get context message') { + cw = { postMessage: () => {} }; + } + + gtcSpy = jest.spyOn(service, 'getTargetContainer').mockImplementation(() => { + return { + iframeHandle: { + iframe: { + contentWindow: cw + } + }, + dispatchEvent: (customEvent) => { + dispatchedEvent = customEvent; + } + }; + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('test alert request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.ALERT_REQUEST, + data: { + id: 'navRequest' + } + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.ALERT_REQUEST); + expect(dispatchedEvent.detail).toEqual({ + data: { data: { id: 'navRequest' }, msg: 'luigi.ux.alert.show' }, + source: {} + }); + }); + + it('test custom message', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.CUSTOM_MESSAGE, + data: { + id: 'custMsgId', + foo: 'bar' + } + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.CUSTOM_MESSAGE); + expect(dispatchedEvent.detail).toEqual({ id: 'custMsgId', _metaData: {}, data: { foo: 'bar' } }); + gtcSpy.mockRestore(); + }); + + it('test get context message', () => { + const event = { + origin: '*', + source: cw, + data: { + msg: LuigiInternalMessageID.GET_CONTEXT, + data: { + id: 'custMsgId', + foo: 'bar' + } + } + }; + + // Create a mock for the postMessage method + const postMessageMock = jest.fn(); + + // Replace the real postMessage with the mock + cw.postMessage = postMessageMock; + + // Define the message to send and target Origin + const message = { + authData: {}, + context: {}, + internal: { + thirdPartyCookieCheck: { + disabled: false + } + }, + msg: 'luigi.init' + }; + const targetOrigin = '*'; + + // Call the method that should trigger postMessage + cm.messageListener(event); + + // Assert that postMessage was called with the expected parameters + expect(postMessageMock).toHaveBeenCalledWith(message, targetOrigin); + + // Clean up by restoring the original postMessage function + cw.postMessage = () => {}; + cw.origin = undefined; + }); + + it('test initialized request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.INITIALIZED, + params: 'init' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.INITIALIZED); + expect(dispatchedEvent.detail).toEqual('init'); + }); + + it('test add search params request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.ADD_SEARCH_PARAMS_REQUEST, + keepBrowserHistory: true, + data: 'some-data' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.ADD_SEARCH_PARAMS_REQUEST); + expect(dispatchedEvent.detail).toEqual({ data: 'some-data', keepBrowserHistory: true }); + }); + + it('test add node params request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.ADD_NODE_PARAMS_REQUEST, + keepBrowserHistory: false, + data: 'some-data' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.ADD_NODE_PARAMS_REQUEST); + expect(dispatchedEvent.detail).toEqual({ data: 'some-data', keepBrowserHistory: false }); + }); + + it('test confirmationModal show request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.SHOW_CONFIRMATION_MODAL_REQUEST, + params: 'modal-show' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.SHOW_CONFIRMATION_MODAL_REQUEST); + }); + + it('test loading indicator show request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.SHOW_LOADING_INDICATOR_REQUEST, + params: 'loading-indicator-show' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.SHOW_LOADING_INDICATOR_REQUEST); + }); + + it('test loading indicator hide request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.HIDE_LOADING_INDICATOR_REQUEST, + params: 'loading-indicator-hide' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.HIDE_LOADING_INDICATOR_REQUEST); + }); + + it('test set locale request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.SET_CURRENT_LOCALE_REQUEST, + params: 'set-locale' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.SET_CURRENT_LOCALE_REQUEST); + }); + + it('test set local storage request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.LOCAL_STORAGE_SET_REQUEST, + params: 'set-local-storage' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.LOCAL_STORAGE_SET_REQUEST); + }); + + it('test runtime error handling request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.RUNTIME_ERROR_HANDLING_REQUEST, + params: 'set-runtime-error-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.RUNTIME_ERROR_HANDLING_REQUEST); + }); + + it('test anchor link request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.SET_ANCHOR_LINK_REQUEST, + params: 'set-anchor-link-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.SET_ANCHOR_LINK_REQUEST); + }); + + it('test third party cookies request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.SET_THIRD_PARTY_COOKIES_REQUEST, + params: 'set-thirdparty-cookies-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.SET_THIRD_PARTY_COOKIES_REQUEST); + }); + + it('test navigation back request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.BACK_NAVIGATION_REQUEST, + params: 'back-navigation-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.BACK_NAVIGATION_REQUEST); + }); + + it('test navigation request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.NAVIGATION_REQUEST, + params: 'navigation-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.NAVIGATION_REQUEST); + }); + + it('test getCurrentRoute request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.GET_CURRENT_ROUTE_REQUEST, + params: 'get-currentroute-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.GET_CURRENT_ROUTE_REQUEST); + }); + + it('test getCurrentRoute request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.GET_CURRENT_ROUTE_REQUEST, + params: 'get-currentroute-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.GET_CURRENT_ROUTE_REQUEST); + }); + + it('test navigation completed request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.NAVIGATION_COMPLETED_REPORT, + params: 'nav-completed-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.NAVIGATION_COMPLETED_REPORT); + }); + + it('test update modalPath data request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.UPDATE_MODAL_PATH_DATA_REQUEST, + params: 'update-modalpathdata-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.UPDATE_MODAL_PATH_DATA_REQUEST); + }); + + it('test check pathExists request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.CHECK_PATH_EXISTS_REQUEST, + params: 'update-check-pathexists-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.CHECK_PATH_EXISTS_REQUEST); + }); + + it('test set dirty status request', () => { + const event = { + source: cw, + data: { + msg: LuigiInternalMessageID.SET_DIRTY_STATUS_REQUEST, + params: 'set-dirtystatus-request' + } + }; + cm.messageListener(event); + expect(dispatchedEvent.type).toEqual(Events.SET_DIRTY_STATUS_REQUEST); + }); + + it('test default', () => { + const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(jest.fn()); + const event = { + source: cw, + data: { + msg: 'no-func' + } + }; + cm.messageListener(event); + expect(consoleWarnSpy).not.toHaveBeenCalled(); + }); +}); + +describe('isVisible', () => { + let service: ContainerService; + service = new ContainerService(); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should return true for a visible element', () => { + // Arrange + const visibleElement = document.createElement('div'); + jest.spyOn(visibleElement, 'offsetWidth', 'get').mockImplementation(() => 200); + document.body.appendChild(visibleElement); + + // Act + const result = service.isVisible(visibleElement); + + // Assert + expect(result).toBe(true); + }); + + it('should return false for a hidden element', () => { + // Arrange + const hiddenElement = document.createElement('div'); + hiddenElement.style.display = 'none'; + document.body.appendChild(hiddenElement); + + // Act + const result = service.isVisible(hiddenElement); + + // Assert + expect(result).toBe(false); + }); + + it('should return false for an element with zero dimensions', () => { + // Arrange + const zeroSizeElement = document.createElement('div'); + zeroSizeElement.style.width = '0'; + zeroSizeElement.style.height = '0'; + document.body.appendChild(zeroSizeElement); + + // Act + const result = service.isVisible(zeroSizeElement); + + // Assert + expect(result).toBe(false); + }); +}); + +describe('sendCustomMessageToIframe', () => { + let service: ContainerService; + service = new ContainerService(); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should send a custom message to the iframe', () => { + // Arrange + const iframeHandle = { + iframe: { + contentWindow: { + postMessage: jest.fn() + }, + src: 'https://example.com' + } + }; + const message = { key: 'value' }; + + // Act + service.sendCustomMessageToIframe(iframeHandle, message); + + // Assert + expect(iframeHandle.iframe.contentWindow.postMessage).toHaveBeenCalledWith( + { msg: 'custom', data: message }, + 'https://example.com' + ); + }); + + it('should send a named message to the iframe', () => { + // Arrange + const iframeHandle = { + iframe: { + contentWindow: { + postMessage: jest.fn() + }, + src: 'https://example.com' + } + }; + const message = { key: 'value' }; + + // Act + service.sendCustomMessageToIframe(iframeHandle, message, 'namedMessage'); + + // Assert + expect(iframeHandle.iframe.contentWindow.postMessage).toHaveBeenCalledWith( + { msg: 'namedMessage', key: 'value' }, + 'https://example.com' + ); + }); + + it('should log an error if contentWindow is not available', () => { + // Arrange + const iframeHandle = { + iframe: {} + }; + const message = { key: 'value' }; + + // Spy on console.error to capture the log message + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + // Act + service.sendCustomMessageToIframe(iframeHandle, message); + + // Assert + expect(consoleErrorSpy).toHaveBeenCalledWith('Message target could not be resolved'); + + // Restore the original console.error function + consoleErrorSpy.mockRestore(); + }); +}); + +describe('dispatch', () => { + let service: ContainerService; + service = new ContainerService(); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should dispatch a custom event to the target container, no Callback', () => { + // Arrange + const targetContainer = document.createElement('div'); + const eventName = 'customEvent'; + const eventData = { key: 'value' }; + targetContainer.dispatchEvent = jest.fn(); + + // Act + service.dispatch(eventName, targetContainer, eventData); + + // Assert + const dispatchedEvent = new CustomEvent(eventName, { detail: eventData }); + expect(targetContainer.dispatchEvent).toHaveBeenCalledWith(dispatchedEvent); + }); + + it('should execute the callback when provided', () => { + // Arrange + const targetContainer = document.createElement('div'); + const eventName = 'customEvent'; + const eventData = { key: 'value' }; + targetContainer.dispatchEvent = jest.fn(); + + // Define a callback function + const callbackFunction = (data) => { + // This function should not be called in this test + }; + + // Act + service.dispatch(eventName, targetContainer, eventData, callbackFunction, 'onCallback'); + + // Assert + globalThis.CustomEvent = jest + .fn() + .mockImplementation((type, eventInit) => ({ isTrusted: false, onCallback: callbackFunction })); + + const dispatchedEventMock = { isTrusted: false, onCallback: expect.any(Function) }; + expect(targetContainer.dispatchEvent).toHaveBeenCalledWith(expect.objectContaining(dispatchedEventMock)); + }); +}); + +describe('getTargetContainer', () => { + let service: ContainerService; + service = new ContainerService(); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should return the correct container when a matching container is found', () => { + // Arrange + const mockContainer1 = { + iframeHandle: { + iframe: { + contentWindow: 'source1' + } + } + }; + const mockContainer2 = { + iframeHandle: { + iframe: { + contentWindow: 'source2' + } + } + }; + + globalThis.__luigi_container_manager = { + container: [mockContainer1, mockContainer2] + }; + + const mockEvent = { + source: 'source2' // Matched with mockContainer2 + }; + + // Act + const targetContainer = service.getTargetContainer(mockEvent); + + // Assert + expect(targetContainer).toBe(mockContainer2); + }); + + it('should return undefined when no matching container is found', () => { + // Arrange + const mockContainer1 = { + iframeHandle: { + iframe: { + contentWindow: 'source1' + } + } + }; + const mockContainer2 = { + iframeHandle: { + iframe: { + contentWindow: 'source2' + } + } + }; + + globalThis.__luigi_container_manager = { + container: [mockContainer1, mockContainer2] + }; + + const mockEvent = { + source: 'source3' // No matching container + }; + + // Act + const targetContainer = service.getTargetContainer(mockEvent); + + // Assert + expect(targetContainer).toBe(undefined); + }); +}); + +describe('getContainerManager branch', () => { + let service: ContainerService; + service = new ContainerService(); + + beforeEach(() => { + globalThis.__luigi_container_manager = undefined; + jest.resetAllMocks(); + }); + + afterEach(() => { + // Reset the global state after each test + globalThis.__luigi_container_manager = undefined; + window.removeEventListener('message', globalThis.__luigi_container_manager?.messageListener); + }); + + it('should initialize and return the container manager', () => { + const containerManager = service.getContainerManager(); + expect(containerManager).toBeDefined(); + expect(containerManager.container).toEqual([]); + expect(containerManager.messageListener).toBeDefined(); + }); + + it('should return the existing container manager if it has been initialized', () => { + const existingManager = { + container: ['existingData'], + messageListener: jest.fn() + }; + globalThis.__luigi_container_manager = existingManager; + + const containerManager = service.getContainerManager(); + expect(containerManager).toBe(existingManager); + }); + + it('should add a message event listener when initializing', () => { + globalThis.__luigi_container_manager = undefined; + const spy = jest.spyOn(window, 'addEventListener'); + + const containerManager = service.getContainerManager(); // Initialize the manager + + // Verify that addEventListener was called with 'message' event type + expect(containerManager).toBeDefined(); + expect(containerManager.container).toEqual([]); + expect(spy).toHaveBeenCalledWith('message', expect.any(Function)); + }); +}); + +describe('registerContainer', () => { + let service: ContainerService; + service = new ContainerService(); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should add an HTMLElement to the container', () => { + // Arrange + const containerManager = { + container: [] + }; + const container = document.createElement('div'); + service.getContainerManager = jest.fn().mockReturnValue(containerManager); + + // Act + service.registerContainer(container); + + // Assert + expect(containerManager.container).toContain(container); + expect(service.getContainerManager).toHaveBeenCalled(); + }); +}); diff --git a/container/typings/LuigiContainer.svelte.d.ts b/container/typings/LuigiContainer.svelte.d.ts index 1264961d11..34fa36e488 100644 --- a/container/typings/LuigiContainer.svelte.d.ts +++ b/container/typings/LuigiContainer.svelte.d.ts @@ -6,7 +6,7 @@ export declare interface WebComponentSettings { export default class LuigiContainer extends HTMLElement { /** - * The URL of the microfrontend to be rendered + * The URL of the microfrontend to be rendered. * @since 1.0.0 * * @example @@ -15,7 +15,7 @@ export default class LuigiContainer extends HTMLElement { viewurl: string; /** - * If set to true defers from initializing the microfronted automatically. In that case init() can be used + * If set to true defers from initializing the microfronted automatically. In that case init() can be used. * @since 1.0.0 * * @example @@ -24,7 +24,7 @@ export default class LuigiContainer extends HTMLElement { deferInit: boolean; /** - * The stringified context object to be passed to the microfrontend + * The stringified context object to be passed to the microfrontend. * @since 1.0.0 * * @@ -34,7 +34,7 @@ export default class LuigiContainer extends HTMLElement { context: string; /** - * Label information for the microfrontend + * Label information for the microfrontend. * @since 1.0.0 * * @example @@ -69,7 +69,7 @@ export default class LuigiContainer extends HTMLElement { webcomponent: boolean | WebComponentSettings | string; /** - * The locale to be passed to the web-component-based micro frontend + * The locale to be passed to the web-component-based micro frontend. * @since 1.0.0 * * @example @@ -78,7 +78,7 @@ export default class LuigiContainer extends HTMLElement { locale: string; /** - * The theme to be passed to the web-component-based micro frontend + * The theme to be passed to the web-component-based micro frontend. * @since 1.0.0 * * @example @@ -87,7 +87,7 @@ export default class LuigiContainer extends HTMLElement { theme: string; /** - * The list of active feature toggles to be passed to the web-component-based micro frontend + * The list of active feature toggles to be passed to the web-component-based micro frontend. * @since 1.0.0 * * @example myContainer.activeFeatureToggleList = ["enable-foo", "allow-bar"] @@ -105,7 +105,7 @@ export default class LuigiContainer extends HTMLElement { skipCookieCheck: boolean; /** - * If set to true, skips handshake and ready event is fired immediately + * If set to true, skips handshake and ready event is fired immediately. * @since 1.0.0 * TODO: https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML says booleans should not use "true"/"false", find a consistent style for our docs. * @example @@ -159,7 +159,7 @@ export default class LuigiContainer extends HTMLElement { clientPermissions: Object; /** - * The user settings to be passed to the web-component-based micro frontend + * The user settings to be passed to the web-component-based micro frontend. * @since 1.0.0 * * @example @@ -224,7 +224,7 @@ export default class LuigiContainer extends HTMLElement { dirtyStatus: boolean; /** - * Function that updates the context of the microfrontend + * Function that updates the context of the microfrontend. * @param {Object} contextObj The context data * @param {Object} internal internal luigi legacy data used for iframes * @example @@ -234,7 +234,7 @@ export default class LuigiContainer extends HTMLElement { updateContext(contextObj: Object, internal?: Object): void; /** - * Send a custom message to the microfronted + * Send a custom message to the microfronted. * @param id a string containing the message id * @param data data to be sent alongside the custom message * @example @@ -244,7 +244,7 @@ export default class LuigiContainer extends HTMLElement { sendCustomMessage(id: string, data?: Object): void; /** - * A function that notifies the microfrontend that the opened alert has been closed + * A function that notifies the microfrontend that the opened alert has been closed. * @param id the id of the opened alert * @param dismissKey the key specifying which dismiss link was clicked on the alert message * @example @@ -254,7 +254,7 @@ export default class LuigiContainer extends HTMLElement { closeAlert(id: string, dismissKey: string): void; /** - * Manually triggers the micro frontend rendering process when using defer-init attribute + * Manually triggers the micro frontend rendering process when using defer-init attribute. * @example * containerElement.init() * @since 1.0.0 diff --git a/core/src/core-api/config.js b/core/src/core-api/config.js index 2dadc375f9..61a44995df 100644 --- a/core/src/core-api/config.js +++ b/core/src/core-api/config.js @@ -18,7 +18,7 @@ class LuigiConfig { * @memberof Configuration */ constructor() { - this.configReadyCallback = function() {}; + this.configReadyCallback = function () {}; this.initialized = false; this.USER_SETTINGS_KEY = 'luigi.preferences.userSettings'; } @@ -104,11 +104,11 @@ class LuigiConfig { configChanged(...scope) { const optimizedScope = StateHelpers.optimizeScope(scope); if (optimizedScope.length > 0) { - optimizedScope.forEach(s => { + optimizedScope.forEach((s) => { window.Luigi._store.fire(s, { current: window.Luigi._store }); }); } else { - window.Luigi._store.update(config => config); + window.Luigi._store.update((config) => config); } } @@ -299,9 +299,9 @@ class LuigiConfig { clearNavigationCache() { NodeDataManagementStorage.deleteCache(); - const clearTitleResolverCache = nodes => { + const clearTitleResolverCache = (nodes) => { if (nodes && nodes.forEach) { - nodes.forEach(node => { + nodes.forEach((node) => { if (node.titleResolver && node.titleResolver._cache) { node.titleResolver._cache = undefined; } @@ -350,7 +350,7 @@ class LuigiConfig { updateContextValues(ctx) { const visibleIframes = IframeHelpers.getMicrofrontendIframes(); if (visibleIframes && visibleIframes.length > 0) { - visibleIframes.forEach(iframe => { + visibleIframes.forEach((iframe) => { // luigi configuration data about the mf which is rendered in the iframe if (iframe.luigi) { IframeHelpers.sendMessageToIframe(iframe, { @@ -368,7 +368,7 @@ class LuigiConfig { } if (document.querySelector('.wcContainer')) { let luiWebComponents = document.querySelectorAll('[lui_web_component=true]'); - luiWebComponents.forEach(luiWebComponent => { + luiWebComponents.forEach((luiWebComponent) => { luiWebComponent.context = Object.assign({}, luiWebComponent.context, ctx); }); } diff --git a/core/src/main.js b/core/src/main.js index e5c5decaaf..c37dbdbf23 100644 --- a/core/src/main.js +++ b/core/src/main.js @@ -10,7 +10,7 @@ const createConfigStore = () => { const scopeSubscribers = {}; let unSubscriptions = []; return { - subscribe: fn => { + subscribe: (fn) => { //subscribe fn returns unsubscription fn unSubscriptions.push(subscribe(fn)); }, @@ -27,13 +27,13 @@ const createConfigStore = () => { fire: (scope, data) => { let subscribers = scopeSubscribers[scope]; if (subscribers) { - [...subscribers].forEach(fn => { + [...subscribers].forEach((fn) => { fn(data); }); } }, clear: () => { - unSubscriptions.forEach(sub => { + unSubscriptions.forEach((sub) => { sub(); }); unSubscriptions = []; @@ -49,7 +49,7 @@ export const getTranslation = readable((key, interpolations, locale) => { Luigi._store = store; const configReadyCallback = () => { - return new Promise(resolve => { + return new Promise((resolve) => { LuigiI18N._init(); AuthLayerSvc.init().then(() => { @@ -69,11 +69,11 @@ const configReadyCallback = () => { } }); - Luigi.showAlert = settings => { + Luigi.showAlert = (settings) => { return app.showAlert(settings); }; - Luigi.showConfirmationModal = settings => { + Luigi.showConfirmationModal = (settings) => { return app.showModal(settings); }; @@ -88,11 +88,11 @@ const configReadyCallback = () => { return app.getGlobalSearchString(); }; - Luigi.setGlobalSearchString = searchString => { + Luigi.setGlobalSearchString = (searchString) => { app.setGlobalSearchString(searchString); }; - Luigi.showSearchResult = arr => { + Luigi.showSearchResult = (arr) => { return app.showSearchResult(arr); }; @@ -115,7 +115,7 @@ const configReadyCallback = () => { } }; - Luigi.pathExists = path => { + Luigi.pathExists = (path) => { return app.pathExists(path); }; diff --git a/core/src/services/routing.js b/core/src/services/routing.js index 85328853f7..e8050811a4 100644 --- a/core/src/services/routing.js +++ b/core/src/services/routing.js @@ -137,10 +137,7 @@ class RoutingClass { } const params = window.location.search ? window.location.search : ''; const path = (window.history.state && window.history.state.path) || window.location.pathname + params; - return path - .split('/') - .slice(1) - .join('/'); + return path.split('/').slice(1).join('/'); } getCurrentPath() { @@ -159,8 +156,8 @@ class RoutingClass { return LuigiConfig.getConfigValue('routing.useHashRouting') ? window.location.hash.replace('#', '') // TODO: GenericHelpers.getPathWithoutHash(window.location.hash) fails in ContextSwitcher : window.location.search - ? GenericHelpers.trimLeadingSlash(window.location.pathname) + window.location.search - : GenericHelpers.trimLeadingSlash(window.location.pathname); + ? GenericHelpers.trimLeadingSlash(window.location.pathname) + window.location.search + : GenericHelpers.trimLeadingSlash(window.location.pathname); } /** @@ -180,7 +177,7 @@ class RoutingClass { const defaultPattern = [/access_token=/, /id_token=/]; const patterns = LuigiConfig.getConfigValue('routing.skipRoutingForUrlPatterns') || defaultPattern; - return patterns.filter(p => location.href.match(p)).length !== 0; + return patterns.filter((p) => location.href.match(p)).length !== 0; } /** @@ -688,7 +685,7 @@ class RoutingClass { this.removeLastChildFromWCContainer(); if (compound && compound.children) { - compound.children = compound.children.filter(c => NavigationHelpers.checkVisibleForFeatureToggles(c)); + compound.children = compound.children.filter((c) => NavigationHelpers.checkVisibleForFeatureToggles(c)); } WebComponentService.renderWebComponentCompound(navNode, wc_container, componentData); wc_container._luigi_pathParams = componentData.pathParams; @@ -822,7 +819,7 @@ class RoutingClass { searchParams.delete(modalParamName); searchParams.delete(`${modalParamName}Params`); let finalUrl = ''; - Array.from(searchParams.keys()).forEach(searchParamKey => { + Array.from(searchParams.keys()).forEach((searchParamKey) => { finalUrl += (finalUrl === '' ? '?' : '&') + searchParamKey + '=' + searchParams.get(searchParamKey); }); url.search = finalUrl; @@ -834,7 +831,7 @@ class RoutingClass { let isModalHistoryHigherThanHistoryLength = false; window.addEventListener( 'popstate', - e => { + (e) => { if (isModalHistoryHigherThanHistoryLength) { //replace the url with saved path and get rid of modal data in url history.replaceState({}, '', path); diff --git a/core/src/utilities/helpers/navigation-helpers.js b/core/src/utilities/helpers/navigation-helpers.js index b4e87c15c4..d03c1f54c1 100644 --- a/core/src/utilities/helpers/navigation-helpers.js +++ b/core/src/utilities/helpers/navigation-helpers.js @@ -41,16 +41,9 @@ class NavigationHelpersClass { prepareForTests(...parts) { let result = ''; - parts.forEach(p => { + parts.forEach((p) => { if (p) { - result += - (result ? '_' : '') + - encodeURIComponent( - p - .toLowerCase() - .split(' ') - .join('') - ); + result += (result ? '_' : '') + encodeURIComponent(p.toLowerCase().split(' ').join('')); } }); return result; @@ -115,7 +108,7 @@ class NavigationHelpersClass { let groupCounter = 0; let virtualGroupCounter = 0; - const orderNodes = nodes => { + const orderNodes = (nodes) => { nodes.sort((a, b) => { const oa = a.order || 0; const ob = b.order || 0; @@ -123,7 +116,7 @@ class NavigationHelpersClass { }); }; - nodes.forEach(node => { + nodes.forEach((node) => { let key; let metaInfo; const category = node[property]; @@ -173,7 +166,7 @@ class NavigationHelpersClass { // Previously we skipped pushing hideFromNav nodes, but we need them now for TabNav logic arr.push(node); }); - Object.keys(result).forEach(category => { + Object.keys(result).forEach((category) => { const metaInfo = result[category].metaInfo; if (metaInfo && metaInfo.id) { result[metaInfo.label] = result[metaInfo.id]; @@ -181,7 +174,7 @@ class NavigationHelpersClass { } }); - Object.keys(result).forEach(category => { + Object.keys(result).forEach((category) => { orderNodes(result[category]); if (result[category].length === 0) { delete result[category]; @@ -215,7 +208,7 @@ class NavigationHelpersClass { let badgeCountsToSumUp = []; for (const node of rawChildren) { - pathData.forEach(n => { + pathData.forEach((n) => { if (!selectedNode && n === node) { selectedNode = node; } @@ -327,7 +320,7 @@ class NavigationHelpersClass { let collapsedList = JSON.parse(localStorage.getItem(this.COLLAPSED_SUPER_CATEGORIES_KEY)) || []; if (value) { - collapsedList = collapsedList.filter(item => item !== key); + collapsedList = collapsedList.filter((item) => item !== key); } else { if (!collapsedList.includes(key)) { collapsedList.push(key); @@ -350,7 +343,7 @@ class NavigationHelpersClass { if (value) { if (replace) { // Filter out other categories - expandedList = expandedList.filter(f => f.indexOf(context + ':') === -1); + expandedList = expandedList.filter((f) => f.indexOf(context + ':') === -1); } if (expandedList.indexOf(key) < 0) { @@ -449,7 +442,7 @@ class NavigationHelpersClass { substituteVars(resolver, context) { const resolverString = JSON.stringify(resolver); - const resString = resolverString.replace(/\$\{[a-zA-Z0-9$_.]+\}/g, match => { + const resString = resolverString.replace(/\$\{[a-zA-Z0-9$_.]+\}/g, (match) => { const chain = match.substr(2, match.length - 3); return this.getPropertyChainValue(context, chain) || match; }); @@ -501,8 +494,8 @@ class NavigationHelpersClass { headers: requestOptions.headers, body: JSON.stringify(requestOptions.body) }) - .then(response => { - response.json().then(data => { + .then((response) => { + response.json().then((data) => { try { const titleData = this.processTitleData(data, resolver, node); node.titleResolver._cache = { @@ -515,10 +508,10 @@ class NavigationHelpersClass { } }); }) - .catch(error => { + .catch((error) => { reject(error); }); - }).catch(error => { + }).catch((error) => { reject(error); }); } diff --git a/core/src/utilities/helpers/routing-helpers.js b/core/src/utilities/helpers/routing-helpers.js index 495da36dc7..c14925bc28 100644 --- a/core/src/utilities/helpers/routing-helpers.js +++ b/core/src/utilities/helpers/routing-helpers.js @@ -22,21 +22,21 @@ class RoutingHelpersClass { const children = childrenResolverFn ? await childrenResolverFn(lastElement, pathData.context) : await AsyncHelpers.getConfigValueFromObjectAsync(lastElement, 'children', pathData.context); - const pathExists = children.find(childNode => childNode.pathSegment === lastElement.defaultChildNode); + const pathExists = children.find((childNode) => childNode.pathSegment === lastElement.defaultChildNode); if (lastElement.defaultChildNode && pathExists) { return lastElement.defaultChildNode; } else if (children && children.length) { const rootPath = pathData.navigationPath.length === 1; if (rootPath) { - const firstNodeWithPathSegment = children.find(child => child.pathSegment); + const firstNodeWithPathSegment = children.find((child) => child.pathSegment); return ( (firstNodeWithPathSegment && firstNodeWithPathSegment.pathSegment) || console.error('At least one navigation node in the root hierarchy must have a pathSegment.') ); } const validChild = children.find( - child => + (child) => child.pathSegment && (child.viewUrl || child.compound || (child.externalLink && child.externalLink.url)) ); if (validChild) return validChild.pathSegment; @@ -51,7 +51,7 @@ class RoutingHelpersClass { const viewParamString = paramsString.replace(/\+/g, ' '); const pairs = viewParamString ? viewParamString.split('&') : null; if (pairs) { - pairs.forEach(pairString => { + pairs.forEach((pairString) => { const keyValue = pairString.split('='); if (keyValue && keyValue.length > 0) { result[decodeURIComponent(keyValue[0])] = decodeURIComponent(keyValue[1]); @@ -73,7 +73,7 @@ class RoutingHelpersClass { const result = {}; const paramPrefix = this.getContentViewParamPrefix(); if (params) { - Object.entries(params).forEach(entry => { + Object.entries(params).forEach((entry) => { if (entry[0].startsWith(paramPrefix)) { const paramName = entry[0].substr(paramPrefix.length); result[paramName] = entry[1]; @@ -174,14 +174,14 @@ class RoutingHelpersClass { addRouteChangeListener(callback) { const hashRoutingActive = LuigiConfig.getConfigValue('routing.useHashRouting'); - EventListenerHelpers.addEventListener('message', e => { + EventListenerHelpers.addEventListener('message', (e) => { if (e.data.msg === 'refreshRoute' && e.origin === window.origin) { const path = hashRoutingActive ? Routing.getHashPath() : Routing.getModifiedPathname(); callback(path); } }); - EventListenerHelpers.addEventListener('popstate', e => { + EventListenerHelpers.addEventListener('popstate', (e) => { const path = hashRoutingActive ? Routing.getHashPath(location.href) : Routing.getModifiedPathname(); callback(path, e.detail); }); @@ -260,8 +260,8 @@ class RoutingHelpersClass { return Object.entries(object) .map(([key, value]) => { const foundKey = contains - ? Object.keys(paramMap).find(key2 => value && value.indexOf(paramPrefix + key2) >= 0) - : Object.keys(paramMap).find(key2 => value === paramPrefix + key2); + ? Object.keys(paramMap).find((key2) => value && value.indexOf(paramPrefix + key2) >= 0) + : Object.keys(paramMap).find((key2) => value === paramPrefix + key2); return [ key, foundKey ? (contains ? value.replace(paramPrefix + foundKey, paramMap[foundKey]) : paramMap[foundKey]) : value @@ -375,7 +375,7 @@ class RoutingHelpersClass { } const featureToggleList = featureTogglesFromUrl.split(','); if (featureToggleList.length > 0 && featureToggleList[0] !== '') { - featureToggleList.forEach(ft => LuigiFeatureToggles.setFeatureToggle(ft, true)); + featureToggleList.forEach((ft) => LuigiFeatureToggles.setFeatureToggle(ft, true)); } } @@ -457,7 +457,7 @@ class RoutingHelpersClass { const intentObject = this.getIntentObject(caseInsensitiveLink); if (intentObject) { let realPath = mappings.find( - item => item.semanticObject === intentObject.semanticObject && item.action === intentObject.action + (item) => item.semanticObject === intentObject.semanticObject && item.action === intentObject.action ); if (!realPath) { return false; @@ -527,7 +527,7 @@ class RoutingHelpersClass { prepareSearchParamsForClient(currentNode) { const filteredObj = {}; if (currentNode && currentNode.clientPermissions && currentNode.clientPermissions.urlParameters) { - Object.keys(currentNode.clientPermissions.urlParameters).forEach(key => { + Object.keys(currentNode.clientPermissions.urlParameters).forEach((key) => { if (key in LuigiRouting.getSearchParams() && currentNode.clientPermissions.urlParameters[key].read === true) { filteredObj[key] = LuigiRouting.getSearchParams()[key]; } @@ -544,7 +544,7 @@ class RoutingHelpersClass { if (currentNode && currentNode.clientPermissions && currentNode.clientPermissions.urlParameters) { const filteredObj = {}; - Object.keys(currentNode.clientPermissions.urlParameters).forEach(key => { + Object.keys(currentNode.clientPermissions.urlParameters).forEach((key) => { if (key in localSearchParams && currentNode.clientPermissions.urlParameters[key].write === true) { filteredObj[key] = localSearchParams[key]; delete localSearchParams[key]; diff --git a/core/test/core-api/config.spec.js b/core/test/core-api/config.spec.js index cd1f09adcb..3a255f37a9 100644 --- a/core/test/core-api/config.spec.js +++ b/core/test/core-api/config.spec.js @@ -78,10 +78,7 @@ describe('updateContextValues', () => { querySelectorStub.withArgs('.wcContainer').returns(mockContainer); - sinon - .stub(document, 'querySelectorAll') - .withArgs('[lui_web_component=true]') - .returns(mockLuiWebComponents); + sinon.stub(document, 'querySelectorAll').withArgs('[lui_web_component=true]').returns(mockLuiWebComponents); const newContext = { updatedContext: 'updated' }; @@ -90,7 +87,7 @@ describe('updateContextValues', () => { sinon.assert.calledWith(querySelectorStub, '.wcContainer'); sinon.assert.calledWith(document.querySelectorAll, '[lui_web_component=true]'); - mockLuiWebComponents.forEach(component => { + mockLuiWebComponents.forEach((component) => { assert.deepEqual(component.context, { initialContext: 'initial', updatedContext: 'updated' }); }); }); @@ -103,7 +100,7 @@ describe('updateContextValues', () => { }; let containerStub = sinon.stub(LuigiElements, 'getLuigiContainer').returns({ firstChild: {}, - removeChild: sinon.spy(function() { + removeChild: sinon.spy(function () { this.firstChild = null; }) }); diff --git a/core/test/utilities/helpers/navigation-helpers.spec.js b/core/test/utilities/helpers/navigation-helpers.spec.js index 5ce9c71d86..11d4fe0ee3 100644 --- a/core/test/utilities/helpers/navigation-helpers.spec.js +++ b/core/test/utilities/helpers/navigation-helpers.spec.js @@ -455,7 +455,7 @@ describe('Navigation-helpers', () => { } }; - it('should reject if no titleResolver set', done => { + it('should reject if no titleResolver set', (done) => { NavigationHelpers.fetchNodeTitleData({ titleResolver: undefined }, {}) .then(() => { assert.fail('Should not be here'); @@ -466,7 +466,7 @@ describe('Navigation-helpers', () => { }); }); - it('should get data from cache', done => { + it('should get data from cache', (done) => { const node = { titleResolver: { url: 'http://localhost' @@ -482,13 +482,13 @@ describe('Navigation-helpers', () => { value: value }; - NavigationHelpers.fetchNodeTitleData(node, node.context).then(data => { + NavigationHelpers.fetchNodeTitleData(node, node.context).then((data) => { assert.equal(data, value); done(); }); }); - it('should use correct request data and properly process response data', done => { + it('should use correct request data and properly process response data', (done) => { const node = JSON.parse(JSON.stringify(samplenode)); let fetchUrl, fetchOptions; @@ -516,7 +516,7 @@ describe('Navigation-helpers', () => { assertRequestData(); done(); }) - .catch(e => { + .catch((e) => { assertRequestData(); done(); }); diff --git a/core/third-party-cookies/init.html b/core/third-party-cookies/init.html index 01014781cc..4c3d9420c2 100644 --- a/core/third-party-cookies/init.html +++ b/core/third-party-cookies/init.html @@ -5,8 +5,8 @@ if (cookies) { luigiCookie = cookies .split(';') - .map(cookie => cookie.trim()) - .find(cookie => cookie == 'luigiCookie=true'); + .map((cookie) => cookie.trim()) + .find((cookie) => cookie == 'luigiCookie=true'); } if (luigiCookie === 'luigiCookie=true') { document.cookie = 'luigiCookie=; Max-Age=-99999999; SameSite=None; Secure'; @@ -16,8 +16,8 @@ if (cookies) { luigiCookie = cookies .split(';') - .map(cookie => cookie.trim()) - .find(cookie => cookie == 'luigiCookie=true'); + .map((cookie) => cookie.trim()) + .find((cookie) => cookie == 'luigiCookie=true'); } if (luigiCookie === 'luigiCookie=true') { window.parent.postMessage('luigi.tpcEnabled', '*'); diff --git a/docs/luigi-container-api.md b/docs/luigi-container-api.md index 8374b42b81..71a2dda932 100644 --- a/docs/luigi-container-api.md +++ b/docs/luigi-container-api.md @@ -25,7 +25,7 @@ In addition you can use standard `addEventListener` function to react on events ### viewurl -The URL of the microfrontend to be rendered +The URL of the microfrontend to be rendered. Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) @@ -45,7 +45,7 @@ myContainer.viewurl = "/index.html" ### deferInit -If set to true defers from initializing the microfronted automatically. In that case init() can be used +If set to true defers from initializing the microfronted automatically. In that case init() can be used. Type: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean) @@ -65,7 +65,7 @@ myContainer.deferInit = true ### context -The stringified context object to be passed to the microfrontend +The stringified context object to be passed to the microfrontend. Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) @@ -85,7 +85,7 @@ myContainer.context = {label: "Dashboard"} ### label -Label information for the microfrontend +Label information for the microfrontend. Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) @@ -144,7 +144,7 @@ myContainer.webcomponent = { type: 'module', selfRegistered: true, tagName: 'my- ### locale -The locale to be passed to the web-component-based micro frontend +The locale to be passed to the web-component-based micro frontend. Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) @@ -164,7 +164,7 @@ myContainer.locale = "en_us" ### theme -The theme to be passed to the web-component-based micro frontend +The theme to be passed to the web-component-based micro frontend. Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) @@ -184,7 +184,7 @@ myContainer.theme = 'sap_horizon' ### activeFeatureToggleList -The list of active feature toggles to be passed to the web-component-based micro frontend +The list of active feature toggles to be passed to the web-component-based micro frontend. Type: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)> @@ -224,7 +224,7 @@ myContainer.skipCookieCheck = true ### skipInitCheck -If set to true, skips handshake and ready event is fired immediately +If set to true, skips handshake and ready event is fired immediately. Type: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean) @@ -345,7 +345,7 @@ myContainer.clientPermissions = {permission: "adminGroup"} ### userSettings -The user settings to be passed to the web-component-based micro frontend +The user settings to be passed to the web-component-based micro frontend. Type: [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) @@ -489,7 +489,7 @@ myContainer.dirtyStatus = true ### updateContext -Function that updates the context of the microfrontend +Function that updates the context of the microfrontend. #### Parameters @@ -510,7 +510,7 @@ Returns **void** ### sendCustomMessage -Send a custom message to the microfronted +Send a custom message to the microfronted. #### Parameters @@ -531,7 +531,7 @@ Returns **void** ### closeAlert -A function that notifies the microfrontend that the opened alert has been closed +A function that notifies the microfrontend that the opened alert has been closed. #### Parameters @@ -552,7 +552,7 @@ Returns **void** ### init -Manually triggers the micro frontend rendering process when using defer-init attribute +Manually triggers the micro frontend rendering process when using defer-init attribute. #### Examples diff --git a/scripts/tools/publish-nightly.js b/scripts/tools/publish-nightly.js index f42aca38c2..7f6b08b496 100644 --- a/scripts/tools/publish-nightly.js +++ b/scripts/tools/publish-nightly.js @@ -15,9 +15,9 @@ import color from 'cli-color'; /** * COLORS */ -const logHeadline = str => console.log(color.bold.cyan(str)); -const logWarning = str => console.log(color.yellow.bold(str)); -const logError = str => console.log(color.redBright.bold(str)); +const logHeadline = (str) => console.log(color.bold.cyan(str)); +const logWarning = (str) => console.log(color.yellow.bold(str)); +const logError = (str) => console.log(color.redBright.bold(str)); const logStep = (s1, s2, s3) => { if (s3) { console.log(color.cyan(s1), color.cyan(s2), color.cyan(s3)); @@ -58,10 +58,7 @@ if (!process.env.NIGHTLY_VERSION) { } function execTrim(cmd) { - return require('child_process') - .execSync(cmd) - .toString() - .trim(); + return require('child_process').execSync(cmd).toString().trim(); } let LATEST_TAG = execTrim('git tag -l | tail -1'); @@ -82,10 +79,10 @@ const FILES_CHANGED = execTrim(`git diff --name-only HEAD ${LATEST_TAG}`); * Checks if files have been changed since last git tag. * @returns changed, a list of packagePaths keys */ - const changed = Object.entries(packagePaths).filter(val => { + const changed = Object.entries(packagePaths).filter((val) => { return ( forcedRelease || - FILES_CHANGED.split('\n').some(file => { + FILES_CHANGED.split('\n').some((file) => { return file.indexOf(val[1].join('/')) !== -1; }) ); @@ -95,11 +92,11 @@ const FILES_CHANGED = execTrim(`git diff --name-only HEAD ${LATEST_TAG}`); logHeadline('\nNothing to publish.'); } else { logHeadline('\nPackages to publish:\n'); - const packagesToUpdate = Object.entries(packagePaths).map(c => c[0]); + const packagesToUpdate = Object.entries(packagePaths).map((c) => c[0]); logStep(packagesToUpdate.join(', ')); logStep('\n'); - packagesToUpdate.forEach(pkg => { + packagesToUpdate.forEach((pkg) => { const publicPath = `${base}/${publishPaths[pkg].join('/')}`; const pkgJson = require(publicPath + '/package.json'); logStep(`Publishing ${pkgJson.name}@${pkgJson.version}`); diff --git a/scripts/tools/release-cli/release-cli.js b/scripts/tools/release-cli/release-cli.js index 9ceb5eaa42..83b7f3b258 100644 --- a/scripts/tools/release-cli/release-cli.js +++ b/scripts/tools/release-cli/release-cli.js @@ -17,9 +17,9 @@ import color from 'cli-color'; /** * COLORS */ -const logHeadline = str => console.log(color.bold.cyan(str)); -const logWarning = str => console.log(color.yellow.bold(str)); -const logError = str => console.log(color.redBright.bold(str)); +const logHeadline = (str) => console.log(color.bold.cyan(str)); +const logWarning = (str) => console.log(color.yellow.bold(str)); +const logError = (str) => console.log(color.redBright.bold(str)); const logStep = (s1, s2, s3) => { if (s3) { console.log(color.cyan(s1), color.cyan(s2), color.cyan(s3)); @@ -82,7 +82,7 @@ async function getReleases() { } }); return JSON.parse(input.body) - .map(r => r.tag_name) + .map((r) => r.tag_name) .filter((t, i) => i <= 8); } @@ -169,7 +169,7 @@ function addToChangelog(versionText, changelog, lastline) { type: 'text', name: 'version', message: 'Version you want to release (current: ' + getVersion('core') + ')?', - validate: str => (semver.valid(str) ? true : 'Invalid version (no valid semver)'), + validate: (str) => (semver.valid(str) ? true : 'Invalid version (no valid semver)'), initial: nextVersion }, { @@ -179,7 +179,7 @@ function addToChangelog(versionText, changelog, lastline) { initial: true }, { - type: prev => (prev == true ? 'select' : null), + type: (prev) => (prev == true ? 'select' : null), name: 'prevVersion', message: 'Previous version to generate from?', choices: releases diff --git a/test/e2e-test-application/cypress/e2e/tests/1-angular/login-flow-nav-dropdown.cy.js b/test/e2e-test-application/cypress/e2e/tests/1-angular/login-flow-nav-dropdown.cy.js index 15dd22ba19..664833db7c 100644 --- a/test/e2e-test-application/cypress/e2e/tests/1-angular/login-flow-nav-dropdown.cy.js +++ b/test/e2e-test-application/cypress/e2e/tests/1-angular/login-flow-nav-dropdown.cy.js @@ -16,9 +16,7 @@ describe('Login Flow', () => { cy.get('[data-testid="luigi-topnav-profile"]').click(); cy.get('[data-testid="luigi-topnav-profile-item"]').contains('Project One'); - cy.get('[data-testid="luigi-topnav-profile-item"]') - .eq(1) - .click(); + cy.get('[data-testid="luigi-topnav-profile-item"]').eq(1).click(); cy.expectPathToBe('/projects/pr1'); @@ -55,7 +53,7 @@ describe('Login Flow', () => { cy.get('[data-testid="luigi-topnav-title"]').should('contain', 'Luigi Demo'); cy.get('[data-testid="luigi-topnav-title"]').should('not.have.attr', 'src', testLogo); - cy.window().then(win => { + cy.window().then((win) => { const config = win.Luigi.getConfig(); config.settings.header.title = testTitle; config.settings.header.logo = testLogo; @@ -101,9 +99,7 @@ describe('TopNavDropDown', () => { cy.get('[data-testid="opengoogleinthistab"]').contains('Open Google in this tab'); - cy.get('[data-testid="all-users_visibleforallusers"]') - .contains('Visible for all users') - .click(); + cy.get('[data-testid="all-users_visibleforallusers"]').contains('Visible for all users').click(); cy.expectPathToBe('/all-users'); }); @@ -120,9 +116,7 @@ describe('TopNavDropDown', () => { //open mobile topnav dropdown cy.get('[data-e2e="mobile-topnav-dropdown-category"][title="Misc"]').click(); - cy.get('[data-e2e="mobile-topnav-item"]') - .contains('Visible for all users') - .click(); + cy.get('[data-e2e="mobile-topnav-item"]').contains('Visible for all users').click(); cy.expectPathToBe('/all-users'); }); diff --git a/test/e2e-test-application/src/logout.html b/test/e2e-test-application/src/logout.html index ffe6bb7931..fb48cc6b70 100644 --- a/test/e2e-test-application/src/logout.html +++ b/test/e2e-test-application/src/logout.html @@ -1,4 +1,4 @@ - + diff --git a/website/docs/src/app.html b/website/docs/src/app.html index 7275db21d4..8ee15127e7 100644 --- a/website/docs/src/app.html +++ b/website/docs/src/app.html @@ -1,4 +1,4 @@ - + @@ -15,7 +15,7 @@
%sveltekit.body%