From 23fa890c6f1f32516b1be23831a0515fef260d78 Mon Sep 17 00:00:00 2001 From: Michael Rochester Date: Thu, 1 Feb 2024 16:46:11 +0000 Subject: [PATCH] test(coverage): coverage --- .../extendWebpackConfig.spec.js.snap | 57 +------ .../utils/extendWebpackConfig.spec.js | 16 ++ .../loaders/__snapshots__/common.spec.js.snap | 148 +----------------- ...erver-ssr-styles-placeholder.spec.js.snap} | 2 +- .../__tests__/webpack/loaders/common.spec.js | 6 + ...dex-server-ssr-styles-placeholder.spec.js} | 2 +- .../webpack/loaders/styles-loader.spec.js | 54 +++++++ .../server-ssr-styles-injector.spec.js.snap | 28 ++++ .../server-ssr-styles-injector.spec.js | 132 ++++++++++++++++ .../one-app-bundler/webpack/loaders/common.js | 6 +- .../plugins/server-ssr-styles-injector.js | 6 +- 11 files changed, 252 insertions(+), 205 deletions(-) rename packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/{index-style-loader.spec.js.snap => index-server-ssr-styles-placeholder.spec.js.snap} (57%) rename packages/one-app-bundler/__tests__/webpack/loaders/{index-style-loader.spec.js => index-server-ssr-styles-placeholder.spec.js} (95%) create mode 100644 packages/one-app-bundler/__tests__/webpack/loaders/styles-loader.spec.js create mode 100644 packages/one-app-bundler/__tests__/webpack/plugins/__snapshots__/server-ssr-styles-injector.spec.js.snap create mode 100644 packages/one-app-bundler/__tests__/webpack/plugins/server-ssr-styles-injector.spec.js diff --git a/packages/one-app-bundler/__tests__/utils/__snapshots__/extendWebpackConfig.spec.js.snap b/packages/one-app-bundler/__tests__/utils/__snapshots__/extendWebpackConfig.spec.js.snap index af360b35..6b9604c8 100644 --- a/packages/one-app-bundler/__tests__/utils/__snapshots__/extendWebpackConfig.spec.js.snap +++ b/packages/one-app-bundler/__tests__/utils/__snapshots__/extendWebpackConfig.spec.js.snap @@ -62,9 +62,9 @@ Object { } `; -exports[`extendWebpackConfig should use the correct trailing slash on windows 1`] = ` +exports[`extendWebpackConfig should use the provided requiredExternals configured, resolved to the js file 1`] = ` Object { - "test": StringMatching /ajv\\\\\\\\\\$/, + "test": StringMatching /ajv\\.js\\$/, "use": Array [ Object { "loader": "@americanexpress/one-app-bundler/webpack/loaders/externals-loader", @@ -77,9 +77,9 @@ Object { } `; -exports[`extendWebpackConfig should use the correct trailing slash on windows 2`] = ` +exports[`extendWebpackConfig should use the provided requiredExternals configured, resolved to the js file 2`] = ` Object { - "test": StringMatching /lodash\\\\\\\\\\$/, + "test": StringMatching /lodash\\.js\\$/, "use": Array [ Object { "loader": "@americanexpress/one-app-bundler/webpack/loaders/externals-loader", @@ -92,54 +92,7 @@ Object { } `; -exports[`extendWebpackConfig should use the correct trailing slash on windows 3`] = ` -Object { - "test": "/path/src/index", - "use": Array [ - Object { - "loader": "@americanexpress/one-app-bundler/webpack/loaders/validate-required-externals-loader", - "options": Object { - "requiredExternals": Array [ - "ajv", - "lodash", - ], - }, - }, - ], -} -`; - -exports[`extendWebpackConfig should use the provided requiredExternals configured 1`] = ` -Object { - "test": StringMatching /ajv\\\\/\\$/, - "use": Array [ - Object { - "loader": "@americanexpress/one-app-bundler/webpack/loaders/externals-loader", - "options": Object { - "bundleTarget": undefined, - "externalName": "ajv", - }, - }, - ], -} -`; - -exports[`extendWebpackConfig should use the provided requiredExternals configured 2`] = ` -Object { - "test": StringMatching /lodash\\\\/\\$/, - "use": Array [ - Object { - "loader": "@americanexpress/one-app-bundler/webpack/loaders/externals-loader", - "options": Object { - "bundleTarget": undefined, - "externalName": "lodash", - }, - }, - ], -} -`; - -exports[`extendWebpackConfig should use the provided requiredExternals configured 3`] = ` +exports[`extendWebpackConfig should use the provided requiredExternals configured, resolved to the js file 3`] = ` Object { "test": "/path/src/index", "use": Array [ diff --git a/packages/one-app-bundler/__tests__/utils/extendWebpackConfig.spec.js b/packages/one-app-bundler/__tests__/utils/extendWebpackConfig.spec.js index fa646dde..e1a8ef03 100644 --- a/packages/one-app-bundler/__tests__/utils/extendWebpackConfig.spec.js +++ b/packages/one-app-bundler/__tests__/utils/extendWebpackConfig.spec.js @@ -201,6 +201,22 @@ describe('extendWebpackConfig', () => { expect(rules[rules.length - 1]).toMatchSnapshot(); }); + it('should use the provided requiredExternals configured, resolved to the js file', async () => { + expect.assertions(4); + getConfigOptions.mockReturnValueOnce({ requiredExternals: ['ajv', 'lodash'] }); + const result = await extendWebpackConfig(originalWebpackConfig); + const { rules } = result.module; + + expect(rules).toHaveLength(originalWebpackConfig.module.rules.length + 3); + expect(rules[rules.length - 3]).toMatchSnapshot({ + test: expect.stringMatching(/ajv.js$/), + }); + expect(rules[rules.length - 2]).toMatchSnapshot({ + test: expect.stringMatching(/lodash.js$/), + }); + expect(rules[rules.length - 1]).toMatchSnapshot(); + }); + it('should enable missing external fallbacks', async () => { expect.assertions(1); getConfigOptions.mockReturnValueOnce({ enableUnlistedExternalFallbacks: true }); diff --git a/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/common.spec.js.snap b/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/common.spec.js.snap index 7fedd97c..7af84a16 100644 --- a/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/common.spec.js.snap +++ b/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/common.spec.js.snap @@ -4,9 +4,9 @@ exports[`Common webpack loaders babel-loader should return a config that extends Object { "loader": "babel-loader", "options": Object { - "cacheDirectory": "/current/dir/.build-cache", + "cacheDirectory": "/mock/path/.build-cache", "envName": "modern", - "extends": "/current/dir/.babelrc", + "extends": "/mock/path/.babelrc", }, } `; @@ -15,149 +15,9 @@ exports[`Common webpack loaders babel-loader should return a config with the exp Object { "loader": "babel-loader", "options": Object { - "cacheDirectory": "/current/dir/.build-cache", + "cacheDirectory": "/mock/path/.build-cache", "envName": "legacy", - "extends": "/current/dir/.babelrc", - }, -} -`; - -exports[`Common webpack loaders css-loader should still return a good localIdentName when not given a chunk name 1`] = ` -Object { - "loader": "css-loader", - "options": Object { - "importLoaders": 2, - "modules": Object { - "getLocalIdent": [Function], - "localIdentName": "[name]__[local]___[hash:base64:5]", - }, - }, -} -`; - -exports[`Common webpack loaders css-loader should still return localName from getLocalIdent if resourcePath includes node_modules 1`] = ` -Object { - "loader": "css-loader", - "options": Object { - "importLoaders": 2, - "modules": Object { - "getLocalIdent": [Function], - "localIdentName": "[name]__[local]___[hash:base64:5]", - }, - }, -} -`; - -exports[`Common webpack loaders css-loader should still return null from getLocalIdent if resourcePath does not include node_modules 1`] = ` -Object { - "loader": "css-loader", - "options": Object { - "importLoaders": 2, - "modules": Object { - "getLocalIdent": [Function], - "localIdentName": "[name]__[local]___[hash:base64:5]", - }, - }, -} -`; - -exports[`Common webpack loaders css-loader should use the chunk name in the localIdentName when given 1`] = ` -Object { - "loader": "css-loader", - "options": Object { - "importLoaders": 2, - "modules": Object { - "getLocalIdent": [Function], - "localIdentName": "my-chunk__[name]__[local]___[hash:base64:5]", - }, - }, -} -`; - -exports[`Common webpack loaders css-loader should use the css-loader 1`] = ` -Object { - "loader": "css-loader", - "options": Object { - "importLoaders": 2, - "modules": Object { - "getLocalIdent": [Function], - "localIdentName": "[name]__[local]___[hash:base64:5]", - }, - }, -} -`; - -exports[`Common webpack loaders purgecss-loader should include any additional configured paths 1`] = ` -Array [ - Object { - "loader": "@americanexpress/purgecss-loader", - "options": Object { - "blocklist": Array [], - "extractors": Array [], - "fontFace": false, - "keyframes": false, - "paths": Array [ - "/current/dir/src/**/*.{js,jsx,ts,tsx}", - "foo", - "bar", - ], - "safelist": Object { - "deep": Array [ - /:global\\$/, - ], - "greedy": Array [], - "keyframes": false, - "standard": Array [], - "variables": false, - }, - "variables": false, - }, - }, -] -`; - -exports[`Common webpack loaders purgecss-loader should return a config that accounts for the src dir 1`] = ` -Array [ - Object { - "loader": "@americanexpress/purgecss-loader", - "options": Object { - "blocklist": Array [], - "extractors": Array [], - "fontFace": false, - "keyframes": false, - "paths": Array [ - "/current/dir/src/**/*.{js,jsx,ts,tsx}", - ], - "safelist": Object { - "deep": Array [ - /:global\\$/, - ], - "greedy": Array [], - "keyframes": false, - "standard": Array [], - "variables": false, - }, - "variables": false, - }, - }, -] -`; - -exports[`Common webpack loaders sass-loader should return a config using dart sass 1`] = ` -Object { - "loader": "sass-loader", - "options": Object { - "implementation": [Function], - "sassOptions": Object { - "includePaths": Array [ - "/current/dir/src", - "/current/dir/node_modules", - ], - "loadPaths": Array [ - "/current/dir/src", - "/current/dir/node_modules", - ], - }, + "extends": "/mock/path/.babelrc", }, } `; diff --git a/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/index-style-loader.spec.js.snap b/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/index-server-ssr-styles-placeholder.spec.js.snap similarity index 57% rename from packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/index-style-loader.spec.js.snap rename to packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/index-server-ssr-styles-placeholder.spec.js.snap index f1379103..a3ebffac 100644 --- a/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/index-style-loader.spec.js.snap +++ b/packages/one-app-bundler/__tests__/webpack/loaders/__snapshots__/index-server-ssr-styles-placeholder.spec.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`index-style-loader should add an ssrStyles export with a uuid placeholder 1`] = ` +exports[`index-server-ssr-styles-placeholder-loader should add an ssrStyles export with a uuid placeholder 1`] = ` " export default SomeModuleName; ;SomeModuleName.ssrStyles = '2574b873-59dc-4da6-8692-d767a2484dac' diff --git a/packages/one-app-bundler/__tests__/webpack/loaders/common.spec.js b/packages/one-app-bundler/__tests__/webpack/loaders/common.spec.js index 94320ed9..4264fdd4 100644 --- a/packages/one-app-bundler/__tests__/webpack/loaders/common.spec.js +++ b/packages/one-app-bundler/__tests__/webpack/loaders/common.spec.js @@ -16,7 +16,13 @@ const { } = require('../../../webpack/loaders/common'); jest.mock('sass', () => () => 0); + +jest.spyOn(process, 'cwd'); + describe('Common webpack loaders', () => { + beforeEach(() => { + process.cwd.mockImplementation(() => '/mock/path/'); + }); describe('babel-loader', () => { it('should return a config that extends the project\'s babelrc', () => { expect(babelLoader('modern')).toMatchSnapshot(); diff --git a/packages/one-app-bundler/__tests__/webpack/loaders/index-style-loader.spec.js b/packages/one-app-bundler/__tests__/webpack/loaders/index-server-ssr-styles-placeholder.spec.js similarity index 95% rename from packages/one-app-bundler/__tests__/webpack/loaders/index-style-loader.spec.js rename to packages/one-app-bundler/__tests__/webpack/loaders/index-server-ssr-styles-placeholder.spec.js index cc57532d..3d05cd26 100644 --- a/packages/one-app-bundler/__tests__/webpack/loaders/index-style-loader.spec.js +++ b/packages/one-app-bundler/__tests__/webpack/loaders/index-server-ssr-styles-placeholder.spec.js @@ -14,7 +14,7 @@ import indexServerSsrStylesPlaceholderLoader from '../../../webpack/loaders/index-server-ssr-styles-placeholder-loader'; -describe('index-style-loader', () => { +describe('index-server-ssr-styles-placeholder-loader', () => { it('should add an ssrStyles export with a uuid placeholder', () => { expect(indexServerSsrStylesPlaceholderLoader('export default SomeModuleName;')).toMatchSnapshot(); }); diff --git a/packages/one-app-bundler/__tests__/webpack/loaders/styles-loader.spec.js b/packages/one-app-bundler/__tests__/webpack/loaders/styles-loader.spec.js new file mode 100644 index 00000000..2be53447 --- /dev/null +++ b/packages/one-app-bundler/__tests__/webpack/loaders/styles-loader.spec.js @@ -0,0 +1,54 @@ +/* + * Copyright 2019 American Express Travel Related Services Company, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations + * under the License. + */ + +import { loadStyles } from '@americanexpress/one-app-dev-bundler'; +import { BUNDLE_TYPES } from '@americanexpress/one-app-dev-bundler/esbuild/constants/enums.js'; +import unboundStylesLoader from '../../../webpack/loaders/styles-loader'; + +jest.mock('@americanexpress/one-app-dev-bundler', () => ({ + loadStyles: jest.fn(() => 'let mockJsContent = "helloMockContent"'), +})); + +describe('styles-loader', () => { + let mockGetOptions; + let stylesLoader; + beforeEach(() => { + jest.clearAllMocks(); + mockGetOptions = jest.fn(() => ({ + cssModulesOptions: {}, + bundleType: BUNDLE_TYPES.BROWSER, + })); + + stylesLoader = unboundStylesLoader.bind({ + resourcePath: 'style/path/mock.scss', + getOptions: mockGetOptions, + }); + }); + it('should call the loadStyles util with the correct params, for non-node_modules', () => { + expect(stylesLoader()).toBe('let mockJsContent = "helloMockContent"'); + expect(loadStyles).toHaveBeenCalledTimes(1); + expect(loadStyles).toHaveBeenCalledWith({ bundleType: BUNDLE_TYPES.BROWSER, cssModulesOptions: { generateScopedName: '[local]_[hash:base64:5]' }, path: 'style/path/mock.scss' }); + }); + it('should call the loadStyles util with the correct params, for node_modules', () => { + stylesLoader = unboundStylesLoader.bind({ + resourcePath: 'node_modules/style/path/mock.scss', + getOptions: mockGetOptions, + }); + + expect(stylesLoader()).toBe('let mockJsContent = "helloMockContent"'); + + expect(loadStyles).toHaveBeenCalledTimes(1); + expect(loadStyles).toHaveBeenCalledWith({ bundleType: BUNDLE_TYPES.BROWSER, cssModulesOptions: { generateScopedName: '[local]' }, path: 'node_modules/style/path/mock.scss' }); + }); +}); diff --git a/packages/one-app-bundler/__tests__/webpack/plugins/__snapshots__/server-ssr-styles-injector.spec.js.snap b/packages/one-app-bundler/__tests__/webpack/plugins/__snapshots__/server-ssr-styles-injector.spec.js.snap new file mode 100644 index 00000000..e08841c0 --- /dev/null +++ b/packages/one-app-bundler/__tests__/webpack/plugins/__snapshots__/server-ssr-styles-injector.spec.js.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ServerSsrStylesInjectorPlugin The registered function should inject the aggregated styles into the placeholder for .node.js files 1`] = ` +" + // replaced + ssrStyles = { + aggregatedStyles: [{\\"css\\":\\"* {color: red}\\",\\"digest\\":\\"digest1Mock\\"},{\\"css\\":\\"* {color: green}\\",\\"digest\\":\\"digest2Mock\\"}], + getFullSheet: function getFullSheet() { + return this.aggregatedStyles.reduce((acc, { css }) => acc + css, ''); + }, +}; + + ===== + + // replaced + ssrStyles = { + aggregatedStyles: [{\\"css\\":\\"* {color: red}\\",\\"digest\\":\\"digest1Mock\\"},{\\"css\\":\\"* {color: green}\\",\\"digest\\":\\"digest2Mock\\"}], + getFullSheet: function getFullSheet() { + return this.aggregatedStyles.reduce((acc, { css }) => acc + css, ''); + }, +}; + + ===== + + // not replaced + ssrStyles = 2574b873-59dc-4da6-8692-d767a2484dac + " +`; diff --git a/packages/one-app-bundler/__tests__/webpack/plugins/server-ssr-styles-injector.spec.js b/packages/one-app-bundler/__tests__/webpack/plugins/server-ssr-styles-injector.spec.js new file mode 100644 index 00000000..521bbfd2 --- /dev/null +++ b/packages/one-app-bundler/__tests__/webpack/plugins/server-ssr-styles-injector.spec.js @@ -0,0 +1,132 @@ +/* + * Copyright 2024 American Express Travel Related Services Company, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations + * under the License. + */ + +import { emptyAggregatedStyles, getAggregatedStyles } from '@americanexpress/one-app-dev-bundler'; +import fs from 'node:fs'; +import ServerSsrStylesInjectorPlugin from '../../../webpack/plugins/server-ssr-styles-injector.js'; +import { + stylesPlaceholderUUID, +} from '../../../webpack/loaders/index-server-ssr-styles-placeholder-loader.js'; + +jest.mock('@americanexpress/one-app-dev-bundler', () => ( + { + emptyAggregatedStyles: jest.fn(), + getAggregatedStyles: jest.fn(() => JSON.stringify([{ css: '* {color: red}', digest: 'digest1Mock' }, { css: '* {color: green}', digest: 'digest2Mock' }])), + } +)); + +const mockStylesPlaceholderUUID = stylesPlaceholderUUID; +jest.mock('node:fs', () => ({ + promises: { + readFile: jest.fn(async () => ` + // replaced + ssrStyles = '${mockStylesPlaceholderUUID}' + + ===== + + // replaced + ssrStyles = "${mockStylesPlaceholderUUID}" + + ===== + + // not replaced + ssrStyles = ${mockStylesPlaceholderUUID} + `), + writeFile: jest.fn(), + }, +})); + +describe('ServerSsrStylesInjectorPlugin', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('should Register an assetEmitted tap hook', () => { + const plugin = new ServerSsrStylesInjectorPlugin(); + + const mockCompiler = { + hooks: { + assetEmitted: { + tap: jest.fn(), + }, + }, + }; + + plugin.apply(mockCompiler); + + expect(mockCompiler.hooks.assetEmitted.tap).toHaveBeenCalledTimes(1); + expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('ServerSsrStylesInjectorPlugin'); + }); + + it('The registered function should inject the aggregated styles into the placeholder for .node.js files', async () => { + expect.assertions(7); + const plugin = new ServerSsrStylesInjectorPlugin(); + + let registeredFn; + const mockCompiler = { + hooks: { + assetEmitted: { + tap: jest.fn((_, fn) => { + registeredFn = fn; + }), + }, + }, + }; + + plugin.apply(mockCompiler); + + expect(registeredFn).not.toBe(undefined); + + await registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.node.js' }); + + expect(fs.promises.readFile).toHaveBeenCalledTimes(1); + expect(fs.promises.writeFile).toHaveBeenCalledTimes(1); + + expect(fs.promises.writeFile.mock.calls[0][1]).toMatchSnapshot(); + + expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('ServerSsrStylesInjectorPlugin'); + + expect(getAggregatedStyles).toHaveBeenCalledTimes(1); + expect(emptyAggregatedStyles).toHaveBeenCalledTimes(1); + }); + it('The registered function should do nothing for non .node.js files', async () => { + expect.assertions(5); + const plugin = new ServerSsrStylesInjectorPlugin(); + + let registeredFn; + const mockCompiler = { + hooks: { + assetEmitted: { + tap: jest.fn((_, fn) => { + registeredFn = fn; + }), + }, + }, + }; + + plugin.apply(mockCompiler); + + expect(registeredFn).not.toBe(undefined); + + await registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.note.js' }); + await registeredFn('fileNameMock.node.js', { targetPath: 'target/Path/Mock.browser.js' }); + await registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.legacyBrowser.js' }); + await registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.something.js' }); + + expect(fs.promises.readFile).toHaveBeenCalledTimes(0); + expect(fs.promises.writeFile).toHaveBeenCalledTimes(0); + + expect(getAggregatedStyles).toHaveBeenCalledTimes(0); + expect(emptyAggregatedStyles).toHaveBeenCalledTimes(0); + }); +}); diff --git a/packages/one-app-bundler/webpack/loaders/common.js b/packages/one-app-bundler/webpack/loaders/common.js index e8be369e..e43633bd 100644 --- a/packages/one-app-bundler/webpack/loaders/common.js +++ b/packages/one-app-bundler/webpack/loaders/common.js @@ -14,13 +14,11 @@ import path from 'node:path'; -const packageRoot = process.cwd(); - export const babelLoader = (babelEnv) => ({ loader: 'babel-loader', options: { - extends: path.join(packageRoot, '.babelrc'), + extends: path.join(process.cwd(), '.babelrc'), envName: babelEnv, - cacheDirectory: path.join(packageRoot, '.build-cache'), + cacheDirectory: path.join(process.cwd(), '.build-cache'), }, }); diff --git a/packages/one-app-bundler/webpack/plugins/server-ssr-styles-injector.js b/packages/one-app-bundler/webpack/plugins/server-ssr-styles-injector.js index 42f314d5..a3bee65e 100644 --- a/packages/one-app-bundler/webpack/plugins/server-ssr-styles-injector.js +++ b/packages/one-app-bundler/webpack/plugins/server-ssr-styles-injector.js @@ -10,9 +10,9 @@ class ServerSsrStylesInjectorPlugin { const initialContent = await fs.promises.readFile(targetPath, 'utf8'); const replacementString = `{ -aggregatedStyles: ${getAggregatedStyles()}, -getFullSheet: function getFullSheet() { - return this.aggregatedStyles.reduce((acc, { css }) => acc + css, ''); + aggregatedStyles: ${getAggregatedStyles()}, + getFullSheet: function getFullSheet() { + return this.aggregatedStyles.reduce((acc, { css }) => acc + css, ''); }, };`;