From 82453440efe1f9c51c18c1a35b641f157747c767 Mon Sep 17 00:00:00 2001 From: Guillermo Cacheda Date: Wed, 9 Aug 2023 12:09:14 +0200 Subject: [PATCH] feat: implement css injector in archetype (#308) EMP-1230 Co-authored-by: Mavi Fdez <77147901+mavmaf@users.noreply.github.com> --- cypress.json | 3 +- package-lock.json | 37 ++++++++++++++++++++----- package.json | 2 +- public/snippet-script.js | 8 ++++++ rollup.config.js | 2 ++ src/main.ts | 2 ++ src/x-components/plugin.options.ts | 28 +++++++++++++++++-- tests/e2e/cucumber/common-steps.spec.ts | 2 ++ tests/e2e/support/index.ts | 8 +++--- 9 files changed, 77 insertions(+), 15 deletions(-) diff --git a/cypress.json b/cypress.json index 878f30d2..7a8713c6 100644 --- a/cypress.json +++ b/cypress.json @@ -9,5 +9,6 @@ "screenshotOnRunFailure": false, "video": false, "testFiles": "**/*.feature", - "retries": 1 + "retries": 1, + "includeShadowDom": true } diff --git a/package-lock.json b/package-lock.json index 0c06f79d..50771cdf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@empathyco/x-adapter": "^8.0.0-alpha.33", "@empathyco/x-adapter-platform": "^1.0.0-alpha.83", - "@empathyco/x-archetype-utils": "^0.1.0-alpha.15", + "@empathyco/x-archetype-utils": "^1.0.0-alpha.3", "@empathyco/x-components": "^3.0.0-alpha.400", "@empathyco/x-deep-merge": "^1.3.0-alpha.29", "@empathyco/x-types": "^10.0.0-alpha.72", @@ -2125,21 +2125,44 @@ "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" }, "node_modules/@empathyco/x-archetype-utils": { - "version": "0.1.0-alpha.15", - "resolved": "https://registry.npmjs.org/@empathyco/x-archetype-utils/-/x-archetype-utils-0.1.0-alpha.15.tgz", - "integrity": "sha512-OzlbY2jZ/VvXcH98xkVwcLa8G6ZIBge3+GntN6BS+foTk7HnIpbKqJWQzkjzQQXN60ZPV7R8V1C2zCC/93RZCg==", + "version": "1.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@empathyco/x-archetype-utils/-/x-archetype-utils-1.0.0-alpha.3.tgz", + "integrity": "sha512-M3INzSFM0SKtwEk0P6gCRKuTQtg+KgPcLkqJAq9NWS0axiuwz7dBwWDCimITTN1550Fcofcz3SCURwthlYI33w==", "dependencies": { - "@empathyco/x-deep-merge": "^1.3.0-alpha.29", - "vue-i18n": "~8.21.0" + "@empathyco/x-deep-merge": "^2.0.0-alpha.2", + "tslib": "~2.5.0", + "vue-i18n": "~8.28.2" }, "engines": { - "node": ">=16" + "node": ">=18" }, "peerDependencies": { "vue": "^2.7.0", "vue-i18n": "^8.0.0" } }, + "node_modules/@empathyco/x-archetype-utils/node_modules/@empathyco/x-deep-merge": { + "version": "2.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/@empathyco/x-deep-merge/-/x-deep-merge-2.0.0-alpha.2.tgz", + "integrity": "sha512-C1/jZ/70oceI9Uxc9tGv692AKuzgl/BAFE1lYN5T1ubgduexI+Z8JgHbV6FTZQBKyGrap3E/o32/5i04naieAQ==", + "dependencies": { + "@empathyco/x-utils": "^1.0.0-alpha.22", + "tslib": "~2.5.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@empathyco/x-archetype-utils/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" + }, + "node_modules/@empathyco/x-archetype-utils/node_modules/vue-i18n": { + "version": "8.28.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.28.2.tgz", + "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==" + }, "node_modules/@empathyco/x-bus": { "version": "1.0.0-alpha.3", "resolved": "https://registry.npmjs.org/@empathyco/x-bus/-/x-bus-1.0.0-alpha.3.tgz", diff --git a/package.json b/package.json index 937cca25..fdb02ae5 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "dependencies": { "@empathyco/x-adapter": "^8.0.0-alpha.33", "@empathyco/x-adapter-platform": "^1.0.0-alpha.83", - "@empathyco/x-archetype-utils": "^0.1.0-alpha.15", + "@empathyco/x-archetype-utils": "^1.0.0-alpha.3", "@empathyco/x-components": "^3.0.0-alpha.400", "@empathyco/x-deep-merge": "^1.3.0-alpha.29", "@empathyco/x-types": "^10.0.0-alpha.72", diff --git a/public/snippet-script.js b/public/snippet-script.js index 03e47912..f1226339 100644 --- a/public/snippet-script.js +++ b/public/snippet-script.js @@ -44,6 +44,12 @@ function getEnv() { return undefined; } +function getIsolationStrategy() { + const isolation = popFromURLParameters('isolation'); + + return isolation === undefined ? undefined : isolation === 'true'; +} + const instance = popFromURLParameters('instance') || 'empathy'; const env = getEnv(); const scope = popFromURLParameters('scope') || 'desktop'; @@ -54,6 +60,7 @@ const currency = popFromURLParameters('currency') || 'EUR'; const consent = popFromURLParameters('consent') !== 'false'; const documentDirection = popFromURLParameters('doc-dir') || 'ltr'; const store = popFromURLParameters('store') || undefined; +const isolate = getIsolationStrategy(); popFromURLParameters('query'); // prevent the query from be included as extra param popFromURLParameters('filter'); // Prevent the filters to be included as extra param @@ -69,6 +76,7 @@ window.initX = { consent, documentDirection, store, + isolate, ...URLParameters, queriesPreview: [ { diff --git a/rollup.config.js b/rollup.config.js index 93c4434b..4e0de20f 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,4 +1,5 @@ import { createConfig } from './build/instrumentation.build'; +import { rollupCssInjectorConfig } from "@empathyco/x-archetype-utils"; export default createConfig({ /* @@ -19,5 +20,6 @@ export default createConfig({ }, plugins: { // Modify plugins options here. + ...rollupCssInjectorConfig } }); diff --git a/src/main.ts b/src/main.ts index a986278b..8feb1157 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,4 @@ +import { CssInjector } from "@empathyco/x-archetype-utils"; import { XInstaller } from '@empathyco/x-components'; import Vue from 'vue'; import { installXOptions } from './x-components/plugin.options'; @@ -11,4 +12,5 @@ declare global { Vue.config.productionTip = false; Vue.config.devtools = window.__enableVueDevtools__ ?? false; +new CssInjector(true); new XInstaller(installXOptions).init(); diff --git a/src/x-components/plugin.options.ts b/src/x-components/plugin.options.ts index 80a77d7a..788a2880 100644 --- a/src/x-components/plugin.options.ts +++ b/src/x-components/plugin.options.ts @@ -1,5 +1,5 @@ -import { InstallXOptions } from '@empathyco/x-components'; -import { I18n } from '@empathyco/x-archetype-utils'; +import { InstallXOptions, SnippetConfig } from '@empathyco/x-components'; +import { I18n, cssInjector } from '@empathyco/x-archetype-utils'; import App from '../App.vue'; import * as messages from '../i18n/messages'; import store from '../store'; @@ -11,6 +11,7 @@ export const installXOptions: InstallXOptions = { adapter, store, app: App, + domElement: getDomElement, xModules: { facets: { config: { @@ -40,3 +41,26 @@ export const installXOptions: InstallXOptions = { }; } }; + +/** + * Creates a DOM element to mount the X Components app. + * + * @param snippetConfig - The snippet configuration. + * @returns The DOM element. + */ +function getDomElement({ isolate }: SnippetConfig): Element { + const domElement = document.createElement('div'); + + if (isolate || process.env.NODE_ENV === 'production') { + const container = document.createElement('div'); + const shadowRoot = container.attachShadow({ mode: 'open' }); + shadowRoot.appendChild(domElement); + document.body.appendChild(container); + cssInjector.setHost(shadowRoot); + } else { + document.body.appendChild(domElement); + cssInjector.setHost(document.head); + } + + return domElement; +} diff --git a/tests/e2e/cucumber/common-steps.spec.ts b/tests/e2e/cucumber/common-steps.spec.ts index dc9fb849..2f88a98a 100644 --- a/tests/e2e/cucumber/common-steps.spec.ts +++ b/tests/e2e/cucumber/common-steps.spec.ts @@ -14,12 +14,14 @@ Then('search bar is clicked', () => { // Search When('a {string} is typed', (query: string) => { + cy.getByDataTest('search-input').should('exist').click(); cy.typeQuery(query).then(() => { cy.getByDataTest('search-input').invoke('val').as('searchedQuery'); }); }); When('{string} is searched', (query: string) => { + cy.getByDataTest('search-input').should('exist').click(); cy.searchQuery(query).then(() => { cy.getByDataTest('search-input').invoke('val').as('searchedQuery'); }); diff --git a/tests/e2e/support/index.ts b/tests/e2e/support/index.ts index da51cde2..f54d8516 100644 --- a/tests/e2e/support/index.ts +++ b/tests/e2e/support/index.ts @@ -101,14 +101,14 @@ type AddPreviousParam> = type CypressCommandOptions = Partial; const customCommands: CustomCommands = { - searchQuery: query => cy.typeQuery(query).type('{enter}'), + searchQuery: query => cy.typeQuery(query).type('{enter}', { force: true }), searchQueries: (...queries) => { queries.forEach(query => { - cy.getByDataTest('search-input').clear(); - cy.typeQuery(query).type('{enter}'); + cy.getByDataTest('search-input').clear({ force: true }); + cy.typeQuery(query).type('{enter}', { force: true }); }); }, - typeQuery: query => cy.getByDataTest('search-input').type(query), + typeQuery: query => cy.getByDataTest('search-input').type(query, { force: true }), focusSearchInput: () => cy.getByDataTest('search-input').click(), clearSearchInput: () => cy.getByDataTest('clear-search-input').click() };