From 7f4a9343deecd5d8fe935dceb14ec598e496541b Mon Sep 17 00:00:00 2001 From: Nicola Molinari Date: Sat, 21 Nov 2020 21:01:43 +0100 Subject: [PATCH] refactor: keep building app-shell as before, until we get rid of css modules --- package.json | 10 +- packages/application-shell/package.json | 18 +- .../application-shell-provider.tsx | 3 +- .../global-style-imports.ts | 4 +- .../{grid.css => grid.mod.css} | 16 +- .../{reset.css => reset.mod.css} | 0 .../src/components/navbar/navbar.tsx | 4 +- .../application-shell/test-utils/index.d.ts | 1 + .../application-shell/test-utils/index.js | 1243 +++++++++++++++++ .../application-shell/test-utils/package.json | 7 - .../tsconfig.declarations.json | 6 + packages/application-shell/tsconfig.json | 4 + 12 files changed, 1282 insertions(+), 34 deletions(-) rename packages/application-shell/src/components/application-shell-provider/{grid.css => grid.mod.css} (74%) rename packages/application-shell/src/components/application-shell-provider/{reset.css => reset.mod.css} (100%) create mode 100644 packages/application-shell/test-utils/index.d.ts create mode 100644 packages/application-shell/test-utils/index.js delete mode 100644 packages/application-shell/test-utils/package.json create mode 100644 packages/application-shell/tsconfig.declarations.json create mode 100644 packages/application-shell/tsconfig.json diff --git a/package.json b/package.json index 141fd53f36..a4b088ba30 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "template-starter:start": "yarn --cwd application-templates/starter start", "template-starter:start:prod:local": "yarn --cwd application-templates/starter start:prod:local", "prebuild": "lerna run prebuild --no-private", - "build": "preconstruct build", + "build": "preconstruct build && yarn workspace @commercetools-frontend/application-shell run build", "build:watch": "preconstruct watch", "build:website": "NODE_ENV=production lerna run build --no-private --scope '@commercetools-frontend/application-components' --include-dependencies && yarn --cwd website build && yarn --cwd website-components-playground build", "now-build": "yarn build:website && rm -rf public && mv website/public public", @@ -71,7 +71,7 @@ "preconstruct": { "packages": [ "packages-backend/*", - "packages/!(assets|babel-preset-mc-app|eslint-config-mc-app|jest-preset-mc-app|jest-stylelint-runner|mc-dev-authentication)" + "packages/!(assets|application-shell|babel-preset-mc-app|eslint-config-mc-app|jest-preset-mc-app|jest-stylelint-runner|mc-dev-authentication)" ] }, "dependencies": { @@ -105,8 +105,10 @@ "@rollup/plugin-node-resolve": "10.0.0", "@testing-library/cypress": "7.0.1", "@testing-library/react": "11.1.2", + "@types/jest-environment-puppeteer": "4.4.0", "@types/jquery": "3.5.4", "@types/node": "14.14.7", + "@types/puppeteer": "5.4.0", "@types/react": "16.9.56", "@types/react-dom": "16.9.9", "@types/react-redux": "7.1.11", @@ -205,9 +207,5 @@ "node": ">=12", "npm": ">=5", "yarn": ">=1.10" - }, - "devDependencies": { - "@types/jest-environment-puppeteer": "4.4.0", - "@types/puppeteer": "5.4.0" } } diff --git a/packages/application-shell/package.json b/packages/application-shell/package.json index 70053c7c7e..bcdeb7f98b 100644 --- a/packages/application-shell/package.json +++ b/packages/application-shell/package.json @@ -15,14 +15,20 @@ "publishConfig": { "access": "public" }, - "main": "dist/application-shell.cjs.js", - "module": "dist/application-shell.esm.js", + "main": "./dist/application-shell-index.cjs.js", + "module": "./dist/application-shell-index.es.js", + "typings": "./dist/typings/index.d.ts", + "types": "./dist/typings/index.d.ts", "files": ["dist", "test-utils", "package.json", "LICENSE", "README.md"], - "preconstruct": { - "entrypoints": [".", "test-utils"] - }, "scripts": { - "prepare": "./../../scripts/version.js replace" + "prepare": "./../../scripts/version.js replace", + "prebuild": "rimraf dist/** test-utils/**", + "build": "yarn build:bundles && yarn build:test-utils && yarn build:typings", + "build:bundles": "cross-env NODE_ENV=production rollup -c ../../rollup.config.js -i ./src/index.ts -d dist", + "build:bundles:watch": "yarn build:bundles -w", + "build:test-utils": "cross-env NODE_ENV=development rollup -c ../../rollup.config.js -i ./src/test-utils/index.ts", + "build:typings": "cross-env tsc -p tsconfig.declarations.json --emitDeclarationOnly --declarationDir dist/typings", + "postbuild:typings": "echo \"export * from '../dist/typings/test-utils';\" > test-utils/index.d.ts" }, "dependencies": { "@babel/runtime": "7.12.5", diff --git a/packages/application-shell/src/components/application-shell-provider/application-shell-provider.tsx b/packages/application-shell/src/components/application-shell-provider/application-shell-provider.tsx index 3c7bf7c8fb..e5ddb43530 100644 --- a/packages/application-shell/src/components/application-shell-provider/application-shell-provider.tsx +++ b/packages/application-shell/src/components/application-shell-provider/application-shell-provider.tsx @@ -3,8 +3,7 @@ import type { TApplicationContext } from '@commercetools-frontend/application-sh import type { TAsyncLocaleDataProps } from '@commercetools-frontend/i18n'; import type { TrackingList } from '../../utils/gtm'; -// FIXME: support loading css files -// import './global-style-imports'; +import './global-style-imports'; import '../../track-performance'; import React from 'react'; import { Router } from 'react-router-dom'; diff --git a/packages/application-shell/src/components/application-shell-provider/global-style-imports.ts b/packages/application-shell/src/components/application-shell-provider/global-style-imports.ts index 54744aef50..ff87ff2fc4 100644 --- a/packages/application-shell/src/components/application-shell-provider/global-style-imports.ts +++ b/packages/application-shell/src/components/application-shell-provider/global-style-imports.ts @@ -1,3 +1,3 @@ // Global MC styles -import './grid.css'; -import './reset.css'; +import './grid.mod.css'; +import './reset.mod.css'; diff --git a/packages/application-shell/src/components/application-shell-provider/grid.css b/packages/application-shell/src/components/application-shell-provider/grid.mod.css similarity index 74% rename from packages/application-shell/src/components/application-shell-provider/grid.css rename to packages/application-shell/src/components/application-shell-provider/grid.mod.css index 1c85773f8b..bb283b8ff4 100644 --- a/packages/application-shell/src/components/application-shell-provider/grid.css +++ b/packages/application-shell/src/components/application-shell-provider/grid.mod.css @@ -3,43 +3,43 @@ TODO: implement a proper layout system with components, or simply use css-grid. */ -.row { +:global(.row) { clear: both; float: left; width: 100%; } -.col-3 { +:global(.col-3) { float: left; width: 25%; } -.col-4 { +:global(.col-4) { float: left; width: 33.333%; } -.col-5 { +:global(.col-5) { float: left; width: 41.666%; } -.col-6 { +:global(.col-6) { float: left; width: 50%; } -.col-7 { +:global(.col-7) { float: left; width: 58.333%; } -.col-8 { +:global(.col-8) { float: left; width: 66.666%; } -.col-12 { +:global(.col-12) { float: left; width: 100%; } diff --git a/packages/application-shell/src/components/application-shell-provider/reset.css b/packages/application-shell/src/components/application-shell-provider/reset.mod.css similarity index 100% rename from packages/application-shell/src/components/application-shell-provider/reset.css rename to packages/application-shell/src/components/application-shell-provider/reset.mod.css diff --git a/packages/application-shell/src/components/navbar/navbar.tsx b/packages/application-shell/src/components/navbar/navbar.tsx index 3fda9a11b7..45e1232ce8 100644 --- a/packages/application-shell/src/components/navbar/navbar.tsx +++ b/packages/application-shell/src/components/navbar/navbar.tsx @@ -45,14 +45,12 @@ import { RestrictedByPermissions } from '@commercetools-frontend/permissions'; import { location } from '../../utils/location'; import { GtmContext } from '../gtm-booter'; import LoadingPlaceholder from '../loading-placeholder'; -// import styles from './navbar.mod.css'; +import styles from './navbar.mod.css'; import messages from './messages'; import useLoadingMenuLayoutEffect from './use-loading-menu-layout-effect'; import useNavbarStateManager from './use-navbar-state-manager'; import nonNullable from './non-nullable'; -// FIXME: migrate css modules to emotion, to avoid having to instruct babel to parse the css file. -const styles: { [key: string]: string } = {}; /* diff --git a/packages/application-shell/test-utils/index.d.ts b/packages/application-shell/test-utils/index.d.ts new file mode 100644 index 0000000000..58649a0422 --- /dev/null +++ b/packages/application-shell/test-utils/index.d.ts @@ -0,0 +1 @@ +export * from '../dist/typings/test-utils'; diff --git a/packages/application-shell/test-utils/index.js b/packages/application-shell/test-utils/index.js new file mode 100644 index 0000000000..54b02ec10f --- /dev/null +++ b/packages/application-shell/test-utils/index.js @@ -0,0 +1,1243 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property'); +var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties'); +var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors'); +var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each'); +var _Object$getOwnPropertyDescriptor = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor'); +var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter'); +var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols'); +var _extends = require('@babel/runtime-corejs3/helpers/extends'); +var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty'); +var _flagsInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/flags'); +var _objectWithoutProperties = require('@babel/runtime-corejs3/helpers/objectWithoutProperties'); +var _valuesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/values'); +var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map'); +var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat'); +var _toConsumableArray = require('@babel/runtime-corejs3/helpers/toConsumableArray'); +var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys'); +var _reduceInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/reduce'); +var React = require('react'); +var PropTypes = require('prop-types'); +var reactRouterDom = require('react-router-dom'); +var invariant = require('tiny-invariant'); +var react = require('@apollo/client/react'); +var testing = require('@apollo/client/testing'); +var rtl = require('@testing-library/react'); +var history$1 = require('history'); +var reactIntl = require('react-intl'); +var reactBroadcast = require('@flopflip/react-broadcast'); +var memoryAdapter = require('@flopflip/memory-adapter'); +var reactRedux = require('react-redux'); +var history = require('@commercetools-frontend/browser-history'); +var applicationShellConnectors = require('@commercetools-frontend/application-shell-connectors'); +var reactNotifications = require('@commercetools-frontend/react-notifications'); +var constants = require('@commercetools-frontend/constants'); +var testUtils = require('@commercetools-frontend/sdk/test-utils'); +var _Reflect$has = require('@babel/runtime-corejs3/core-js-stable/reflect/has'); +var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray'); +var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries'); +var redux = require('redux'); +var thunk = require('redux-thunk'); +var notifications = require('@commercetools-frontend/notifications'); +var sdk = require('@commercetools-frontend/sdk'); +var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes'); +var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with'); +var reduxLogger = require('redux-logger'); +var _URL = require('@babel/runtime-corejs3/core-js-stable/url'); +require('react-dom'); +require('@commercetools-uikit/loading-spinner'); +var core = require('@emotion/core'); +var _sliceInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/slice'); +var _indexOfInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/index-of'); +var sentry = require('@commercetools-frontend/sentry'); +var uuid = require('uuid'); +var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find'); +var client = require('@apollo/client'); +var createHttpUserAgent = require('@commercetools/http-user-agent'); +var loggerLink = require('apollo-link-logger'); +var _getIterator = require('@babel/runtime-corejs3/core-js/get-iterator'); +var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-array'); +var _getIteratorMethod = require('@babel/runtime-corejs3/core-js/get-iterator-method'); +var _Symbol = require('@babel/runtime-corejs3/core-js-stable/symbol'); +var _Array$from = require('@babel/runtime-corejs3/core-js-stable/array/from'); +var error = require('@apollo/client/link/error'); +var _someInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/some'); +var _Object$values = require('@babel/runtime-corejs3/core-js-stable/object/values'); +var omitEmpty = require('omit-empty-es'); +var retry = require('@apollo/client/link/retry'); + +function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } + +var _Object$defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_Object$defineProperty); +var _Object$defineProperties__default = /*#__PURE__*/_interopDefaultLegacy(_Object$defineProperties); +var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefaultLegacy(_Object$getOwnPropertyDescriptors); +var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_forEachInstanceProperty); +var _Object$getOwnPropertyDescriptor__default = /*#__PURE__*/_interopDefaultLegacy(_Object$getOwnPropertyDescriptor); +var _filterInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_filterInstanceProperty); +var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefaultLegacy(_Object$getOwnPropertySymbols); +var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends); +var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty); +var _flagsInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_flagsInstanceProperty); +var _objectWithoutProperties__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutProperties); +var _valuesInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_valuesInstanceProperty); +var _mapInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_mapInstanceProperty); +var _concatInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_concatInstanceProperty); +var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray); +var _Object$keys__default = /*#__PURE__*/_interopDefaultLegacy(_Object$keys); +var _reduceInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_reduceInstanceProperty); +var React__default = /*#__PURE__*/_interopDefaultLegacy(React); +var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes); +var invariant__default = /*#__PURE__*/_interopDefaultLegacy(invariant); +var memoryAdapter__default = /*#__PURE__*/_interopDefaultLegacy(memoryAdapter); +var history__default = /*#__PURE__*/_interopDefaultLegacy(history); +var _Reflect$has__default = /*#__PURE__*/_interopDefaultLegacy(_Reflect$has); +var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray); +var _Object$entries__default = /*#__PURE__*/_interopDefaultLegacy(_Object$entries); +var thunk__default = /*#__PURE__*/_interopDefaultLegacy(thunk); +var _includesInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_includesInstanceProperty); +var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_startsWithInstanceProperty); +var _URL__default = /*#__PURE__*/_interopDefaultLegacy(_URL); +var _sliceInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_sliceInstanceProperty); +var _indexOfInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_indexOfInstanceProperty); +var _findInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_findInstanceProperty); +var createHttpUserAgent__default = /*#__PURE__*/_interopDefaultLegacy(createHttpUserAgent); +var loggerLink__default = /*#__PURE__*/_interopDefaultLegacy(loggerLink); +var _getIterator__default = /*#__PURE__*/_interopDefaultLegacy(_getIterator); +var _Array$isArray__default = /*#__PURE__*/_interopDefaultLegacy(_Array$isArray); +var _getIteratorMethod__default = /*#__PURE__*/_interopDefaultLegacy(_getIteratorMethod); +var _Symbol__default = /*#__PURE__*/_interopDefaultLegacy(_Symbol); +var _Array$from__default = /*#__PURE__*/_interopDefaultLegacy(_Array$from); +var _someInstanceProperty__default = /*#__PURE__*/_interopDefaultLegacy(_someInstanceProperty); +var _Object$values__default = /*#__PURE__*/_interopDefaultLegacy(_Object$values); +var omitEmpty__default = /*#__PURE__*/_interopDefaultLegacy(omitEmpty); + +var isAddNotificationErrorAction = function isAddNotificationErrorAction(action) { + var errorAction = action; + return errorAction.type === notifications.ADD_NOTIFICATION && errorAction.payload && (errorAction.payload.kind === constants.NOTIFICATION_KINDS_PAGE['api-error'] || errorAction.payload.kind === constants.NOTIFICATION_KINDS_PAGE['unexpected-error']); +}; + +var isHideAllNotificationsAction = function isHideAllNotificationsAction(action) { + return action.type === constants.HIDE_ALL_PAGE_NOTIFICATIONS; +}; + +var hideNotificationsMiddleware = (function (_ref) { + var getState = _ref.getState; + return function (next) { + return function (action) { + if (isHideAllNotificationsAction(action) || isAddNotificationErrorAction(action)) { + var _context; + + var state = getState(); + + _forEachInstanceProperty__default['default'](_context = reactNotifications.selectPageNotifications(state)).call(_context, function (notification) { + next(notifications.removeNotification(notification.id)); + }); + } + + return next(action); + }; + }; +}); + +/* eslint-disable no-console */ +var isLoggerEnabled = function isLoggerEnabled() { + if (process.env.DEBUG === 'true') return true; + if (process.env.NODE_ENV === 'development') return true; + var queryParams = new _URL__default['default'](window.location.href); + if (process.env.NODE_ENV === 'production' && queryParams.searchParams.get('debug') === 'true') return true; + return false; +}; +var logger = { + groupCollapsed: function groupCollapsed() { + var _console; + + return isLoggerEnabled() && (_console = console).groupCollapsed.apply(_console, arguments); + }, + groupEnd: function groupEnd() { + return isLoggerEnabled() && console.groupEnd(); + }, + info: function info() { + var _console2; + + return isLoggerEnabled() && (_console2 = console).info.apply(_console2, arguments); + }, + log: function log() { + var _console3; + + return isLoggerEnabled() && (_console3 = console).log.apply(_console3, arguments); + }, + error: function error() { + var _console4; + + return isLoggerEnabled() && (_console4 = console).error.apply(_console4, arguments); + }, + warn: function warn() { + var _console5; + + return isLoggerEnabled() && (_console5 = console).warn.apply(_console5, arguments); + } +}; + +var loggerMiddleware = reduxLogger.createLogger({ + logger: logger, + collapsed: true, + colors: { + title: function title() { + return '#000000'; + }, + prevState: function prevState() { + return '#9E9E9E'; + }, + action: function action() { + return '#03A9F4'; + }, + nextState: function nextState() { + return '#4CAF50'; + }, + error: function error() { + return '#F20404'; + } + }, + // WARNING: Enabling this option causes huge performance degradation. + // Only enable if you want detailed debugging. + diff: false, + predicate: function predicate(_getState, action) { + if (!action) return false; + var type = action.type, + payload = action.payload; + if (!type) return false; + if (_startsWithInstanceProperty__default['default'](type).call(type, 'SHOW_') || _startsWithInstanceProperty__default['default'](type).call(type, 'HIDE_') || _startsWithInstanceProperty__default['default'](type).call(type, 'APOLLO_')) return false; + + switch (type) { + case notifications.REMOVE_NOTIFICATION: + return false; + + case notifications.ADD_NOTIFICATION: + { + var ignoredKinds = ['api-error', 'unexpected-error']; + return !_includesInstanceProperty__default['default'](ignoredKinds).call(ignoredKinds, payload.kind); + } + + default: + return true; + } + } +}); + +reactIntl.defineMessages({ + labelLoading: { + // Keep the id for backwards compatibility. + // TODO: provide a new key? + id: 'TopNavigation.labelLoading', + description: 'The text to show next to the loading icon', + defaultMessage: 'Processing...' + } +}); + +var isShowRequestInFlightAction = function isShowRequestInFlightAction(action) { + return action.type === constants.SHOW_LOADING; +}; + +var isHideRequestInFlightAction = function isHideRequestInFlightAction(action) { + return action.type === constants.HIDE_LOADING; +}; + +var excludeFirstOccurrence = function excludeFirstOccurrence(list, item) { + var _context; + + var index = _indexOfInstanceProperty__default['default'](list).call(list, item); + + return _concatInstanceProperty__default['default'](_context = []).call(_context, _toConsumableArray__default['default'](_sliceInstanceProperty__default['default'](list).call(list, 0, index)), _toConsumableArray__default['default'](_sliceInstanceProperty__default['default'](list).call(list, index + 1))); +}; + +var requestsInFlightReducer = (function (requestsInFlight, action) { + var _context2; + + if (!requestsInFlight || !action) return []; + if (isShowRequestInFlightAction(action)) return _concatInstanceProperty__default['default'](_context2 = []).call(_context2, _toConsumableArray__default['default'](requestsInFlight), [action.payload]); + + if (isHideRequestInFlightAction(action)) { + // may only remove first occurence + if (!_includesInstanceProperty__default['default'](requestsInFlight).call(requestsInFlight, action.payload)) { + sentry.reportErrorToSentry(new Error("Tried to hide \"".concat(action.payload, "\", but it was not progressing!"))); + return requestsInFlight; + } + + return excludeFirstOccurrence(requestsInFlight, action.payload); + } + + return requestsInFlight; +}); + +var SUPPORTED_HEADERS = { + ACCEPT_VERSION: 'Accept-version', + X_APPLICATION_ID: 'X-Application-Id', + X_CORRELATION_ID: 'X-Correlation-Id', + X_FEATURE_FLAG: 'X-Feature-Flag', + X_FORWARD_TO: 'X-Forward-To', + X_GRAPHQL_TARGET: 'X-Graphql-Target', + X_GRAPHQL_OPERATION_NAME: 'X-Graphql-Operation-Name', + X_PROJECT_KEY: 'X-Project-Key', + X_TEAM_ID: 'X-Team-Id', + X_TOKEN_RETRY: 'X-Force-Token' +}; +var STORAGE_KEYS = { + NONCE: 'nonce', + IS_AUTHENTICATED: 'isAuthenticated', + ACTIVE_PROJECT_KEY: 'activeProjectKey', + ACTIVE_TEAM_ID: 'activeTeamId', + SELECTED_DATA_LOCALE: 'selectedDataLocale', + IS_FORCED_MENU_OPEN: 'isForcedMenuOpen', + LOGIN_STRATEGY: 'loginStrategy' +}; + +function selectTeamIdFromLocalStorage() { + return window.localStorage.getItem(STORAGE_KEYS.ACTIVE_TEAM_ID) || undefined; +} + +var staticUrlPathsInPositionOfProjectKey = ['login', 'logout', 'account']; // Attempt to extract the `:projectKey` from the URL. +// If the value matches one of the values in the list above, +// return `undefined` as we're not within a project context. + +function selectProjectKeyFromUrl() { + var locationPath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.location.pathname; + var possibleProjectKey = locationPath.split('/')[1]; + return _includesInstanceProperty__default['default'](staticUrlPathsInPositionOfProjectKey).call(staticUrlPathsInPositionOfProjectKey, possibleProjectKey) ? undefined : possibleProjectKey; +} + +function selectUserId() { + + { + return null; + } +} + +var VALID_ID_PART_FORMAT = /^[\w-/]+$/; + +var skipMalformedPart = function skipMalformedPart(part) { + return part && VALID_ID_PART_FORMAT.test(part); +}; + +function getCorrelationId() { + var _context; + + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + userId = _ref.userId; + + return _filterInstanceProperty__default['default'](_context = ['mc', selectProjectKeyFromUrl(), userId, uuid.v4()]).call(_context, skipMalformedPart).join('/'); +} + +var removeMcPrefix = function removeMcPrefix(host) { + return host.replace(/^mc(-(\d){4,})?\.(.*)$/, '$3'); +}; +/** + * NOTE: + * Given the Merchant Center or Custom Application runs behind the proxy + * then the `mcApiUrl` should be build using the origin on the window. + * + * This allows the Merchant Center (or any Custom Appliction) to automatically + * use an `mcApiUrl` which matches the respective url of the deployment. + * + * This is particularily useful with the new and old hostnames for the Merchant Center. + * When using the origin, it will be made sure that the authorization cookie will + * always be sent as the appropriate API url is used. + * + * 1. MC: mc.commercetools.com with API: mc-api.europe-west1.gcp.commercetools.com + * -> Will not work as urls differ + * 2. MC: mc.europe-west1.gcp.commercetools.com with API: mc-api.commercetools.com + * -> Will not work as urls differ + * + * Using the origin ensures that urls always match with the cookie sent. Otherwise, + * the application shell will rightfully redirect to the logout page. + */ + + +var getMcApiUrlFromOrigin = function getMcApiUrlFromOrigin(actualWindow) { + var _context; + + var url = new _URL__default['default'](actualWindow.origin); + var originTld = removeMcPrefix(url.host); + return _concatInstanceProperty__default['default'](_context = "".concat(url.protocol, "//mc-api.")).call(_context, originTld); +}; + +var isEnvironmentConfigurationEnabled = function isEnvironmentConfigurationEnabled(environmentConfiguration) { + return environmentConfiguration === true || environmentConfiguration === 'true'; +}; + +function getMcApiUrl() { + var actualWindow = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window; + var isServedByProxy = isEnvironmentConfigurationEnabled(actualWindow.app.servedByProxy); + + if (isServedByProxy) { + return getMcApiUrlFromOrigin(actualWindow); + } + + return actualWindow.app.mcApiUrl; +} + +function ownKeys(object, enumerableOnly) { var keys = _Object$keys__default['default'](object); if (_Object$getOwnPropertySymbols__default['default']) { var symbols = _Object$getOwnPropertySymbols__default['default'](object); if (enumerableOnly) symbols = _filterInstanceProperty__default['default'](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default['default'](object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context3; _forEachInstanceProperty__default['default'](_context3 = ownKeys(Object(source), true)).call(_context3, function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors__default['default']) { _Object$defineProperties__default['default'](target, _Object$getOwnPropertyDescriptors__default['default'](source)); } else { var _context4; _forEachInstanceProperty__default['default'](_context4 = ownKeys(Object(source))).call(_context4, function (key) { _Object$defineProperty__default['default'](target, key, _Object$getOwnPropertyDescriptor__default['default'](source, key)); }); } } return target; } + +var identityStoreEnhancer = function identityStoreEnhancer(noop) { + return noop; +}; + +var mergeObjectValues = function mergeObjectValues(object) { + var _context; + + return _reduceInstanceProperty__default['default'](_context = _Object$entries__default['default'](object)).call(_context, function (acc, _ref) { + var _ref2 = _slicedToArray__default['default'](_ref, 2), + value = _ref2[1]; + + return _objectSpread(_objectSpread({}, acc), value); + }, {}); +}; + +var patchedGetCorrelationId = function patchedGetCorrelationId() { + return getCorrelationId({ + userId: selectUserId() + }); +}; + +var createInternalReducer = function createInternalReducer() { + var injectedReducers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + return (// NOTE: since we don't know in advance which reducers will be injected, + // we pass an `unknown` type to express this uncertainty and make the compiler happy. + redux.combineReducers(_objectSpread({ + requestsInFlight: requestsInFlightReducer, + notifications: notifications.reducer + }, injectedReducers)) + ); +}; + +var sdkMiddleware = sdk.createMiddleware({ + getCorrelationId: patchedGetCorrelationId, + getProjectKey: selectProjectKeyFromUrl, + getTeamId: selectTeamIdFromLocalStorage +}); +var applyDefaultMiddlewares = function applyDefaultMiddlewares() { + for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) { + middlewares[_key] = arguments[_key]; + } + + return redux.applyMiddleware.apply(void 0, _concatInstanceProperty__default['default'](middlewares).call(middlewares, [thunk__default['default'], loggerMiddleware])); +}; // We use a factory as it's more practicable for tests +// The application can import the configured store (the default export) + +var createReduxStore = function createReduxStore() { + var _context2; + + var preloadedState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var additionalMiddlewares = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + var store = redux.createStore(createInternalReducer(), preloadedState, redux.compose(applyDefaultMiddlewares.apply(void 0, _concatInstanceProperty__default['default'](_context2 = _toConsumableArray__default['default'](additionalMiddlewares)).call(_context2, [hideNotificationsMiddleware, notifications.middleware, sdkMiddleware])), window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__({ + actionsBlacklist: [constants.SHOW_LOADING, constants.HIDE_LOADING] + }) : identityStoreEnhancer)); + var enhancedStore = store; // Enable reducers to be injected on runtime (see ``) + + enhancedStore.injectedReducers = {}; + + enhancedStore.injectReducers = function (_ref3) { + var id = _ref3.id, + reducers = _ref3.reducers; + var hasReducerBeenInjected = _Reflect$has__default['default'](enhancedStore.injectedReducers, id) && enhancedStore.injectedReducers[id] === reducers; + + if (!hasReducerBeenInjected) { + // Keep track of the reducer by id, so we can check if it's been injected aleady + enhancedStore.injectedReducers[id] = reducers; // ...when we create the new reducer though, we spread the reducers from each namespace + + enhancedStore.replaceReducer(createInternalReducer(mergeObjectValues(enhancedStore.injectedReducers))); + } + }; + + enhancedStore.removeReducers = function (_ref4) { + var id = _ref4.id; + delete enhancedStore.injectedReducers[id]; + enhancedStore.replaceReducer(createInternalReducer(mergeObjectValues(enhancedStore.injectedReducers))); + }; + + return enhancedStore; +}; +createReduxStore(); + +function ownKeys$1(object, enumerableOnly) { var keys = _Object$keys__default['default'](object); if (_Object$getOwnPropertySymbols__default['default']) { var symbols = _Object$getOwnPropertySymbols__default['default'](object); if (enumerableOnly) symbols = _filterInstanceProperty__default['default'](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default['default'](object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context2; _forEachInstanceProperty__default['default'](_context2 = ownKeys$1(Object(source), true)).call(_context2, function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors__default['default']) { _Object$defineProperties__default['default'](target, _Object$getOwnPropertyDescriptors__default['default'](source)); } else { var _context3; _forEachInstanceProperty__default['default'](_context3 = ownKeys$1(Object(source))).call(_context3, function (key) { _Object$defineProperty__default['default'](target, key, _Object$getOwnPropertyDescriptor__default['default'](source, key)); }); } } return target; } + +var getSkipTokenRetry = function getSkipTokenRetry(context) { + var skipTokenRetry = Boolean(context.skipTokenRetry); + return skipTokenRetry; +}; + +var forwardTokenRetryHeader = function forwardTokenRetryHeader(headers) { + return _objectSpread$1(_objectSpread$1({}, headers), {}, _defineProperty__default['default']({}, SUPPORTED_HEADERS.X_TOKEN_RETRY, 'true')); +}; // This link retries requests to the CTP API that have been rejected +// because of an invalid/expired oauth token. +// To do so, we resend the request with the header "X-Force-Token: true" +// so that the MC BE can issue a new token. +// NOTE: the retry is not meant to work for the MC access token. + + +var getDoesGraphQLTargetSupportTokenRetry = function getDoesGraphQLTargetSupportTokenRetry(context) { + var _context$headers, _context$headers2, _context; + + var graphQLTarget = ((_context$headers = context.headers) === null || _context$headers === void 0 ? void 0 : _context$headers[SUPPORTED_HEADERS.X_GRAPHQL_TARGET]) || ((_context$headers2 = context.headers) === null || _context$headers2 === void 0 ? void 0 : _context$headers2[SUPPORTED_HEADERS.X_GRAPHQL_TARGET.toLowerCase()]); + return Boolean(graphQLTarget && _includesInstanceProperty__default['default'](_context = [constants.GRAPHQL_TARGETS.COMMERCETOOLS_PLATFORM, constants.GRAPHQL_TARGETS.ADMINISTRATION_SERVICE, constants.GRAPHQL_TARGETS.SETTINGS_SERVICE, constants.GRAPHQL_TARGETS.MERCHANT_CENTER_BACKEND]).call(_context, graphQLTarget)); +}; + +var isHttpError = function isHttpError(error) { + return error.statusCode !== undefined || error.statusCode !== undefined; +}; + +var isGraphQLError = function isGraphQLError(error) { + return _Array$isArray__default['default'](error) && _someInstanceProperty__default['default'](error).call(error, function (err) { + return err.message !== undefined || err.extensions !== undefined; + }); +}; + +function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof _Symbol__default['default'] === "undefined" || _getIteratorMethod__default['default'](o) == null) { if (_Array$isArray__default['default'](o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = _getIterator__default['default'](o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } + +function _unsupportedIterableToArray(o, minLen) { var _context; if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = _sliceInstanceProperty__default['default'](_context = Object.prototype.toString.call(o)).call(_context, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return _Array$from__default['default'](o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } + +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +// user to the login page resetting the store and showing the proper message + +var errorLink = error.onError(function (_ref) { + var graphQLErrors = _ref.graphQLErrors, + networkError = _ref.networkError, + operation = _ref.operation, + forward = _ref.forward; + + if (networkError && isHttpError(networkError) && networkError.statusCode === constants.STATUS_CODES.UNAUTHORIZED) { + history__default['default'].push("/logout?reason=".concat(constants.LOGOUT_REASONS.UNAUTHORIZED)); + return; + } // In case of graphql errors, we want to retry unauthenticated requests by + // forcing our API to fetch a new token, using the `X-Force-Token` header. + // https://www.apollographql.com/docs/link/links/error/#retrying-failed-requests + // We need to do this as the `token-retry-link` only works for network errors. + // https://www.apollographql.com/docs/link/links/retry/ + + + if (graphQLErrors && isGraphQLError(graphQLErrors)) { + var context = operation.getContext(); + + var _iterator = _createForOfIteratorHelper(graphQLErrors), + _step; + + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var _err$extensions; + + var err = _step.value; + var isNonAuthenticatedViaExtensionCode = (err === null || err === void 0 ? void 0 : (_err$extensions = err.extensions) === null || _err$extensions === void 0 ? void 0 : _err$extensions.code) === 'UNAUTHENTICATED'; + /** + * NOTE: + * Not not all GraphQL APIs expose an `extensions` field in + * each error. For those we have to use the `message` + * property until they introduced support for the `extensions` + * field. + */ + + var isNonAuthenticatedViaCode = (err === null || err === void 0 ? void 0 : err.message) === 'invalid_token'; + + if ((isNonAuthenticatedViaExtensionCode || isNonAuthenticatedViaCode) && getDoesGraphQLTargetSupportTokenRetry(context) && !getSkipTokenRetry(context)) { + operation.setContext(function (_ref2) { + var headers = _ref2.headers; + return { + headers: forwardTokenRetryHeader(headers) + }; + }); // retry the request, returning the new observable + + return forward(operation); + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } + + return; +}); + +var isKnownGraphQlTarget = function isKnownGraphQlTarget(target) { + var _context; + + return target ? _includesInstanceProperty__default['default'](_context = _Object$values__default['default'](constants.GRAPHQL_TARGETS)).call(_context, target) : false; +}; +/* eslint-disable import/prefer-default-export */ +// Use a middleware to update the request headers with the correct params. + + +var headerLink = new client.ApolloLink(function (operation, forward) { + var _omitEmpty; + + var apolloContext = operation.getContext(); + var variables = operation.variables; + var graphQlTarget = apolloContext.target || variables.target; + if (!apolloContext.skipGraphQlTargetCheck && !isKnownGraphQlTarget(graphQlTarget)) throw new Error("GraphQL target \"".concat(graphQlTarget, "\" is missing or is not supported")); + /** + * NOTE: + * The project key is read from the url in a project related appliation context. + * This holds for most applications like `application-categories`, `application-discounts` etc. + * However, the `application-account` does not run with the project key being part of the url. + * As a result we allow passing the project key as a variable on the operation allowing + * it to be the fallback. + */ + + var projectKey = apolloContext.projectKey || variables.projectKey || selectProjectKeyFromUrl(); + var teamId = apolloContext.teamId || variables.teamId || selectTeamIdFromLocalStorage(); + var userId = selectUserId(); + var featureFlag = apolloContext.featureFlag || variables.featureFlag; + operation.setContext({ + credentials: 'include', + headers: omitEmpty__default['default']((_omitEmpty = {}, _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_PROJECT_KEY, projectKey), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_CORRELATION_ID, getCorrelationId({ + userId: userId + })), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_GRAPHQL_TARGET, graphQlTarget), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_GRAPHQL_OPERATION_NAME, operation.operationName), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_TEAM_ID, teamId), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_APPLICATION_ID, window.app.applicationId), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_FEATURE_FLAG, featureFlag), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.ACCEPT_VERSION, apolloContext.forwardToConfig ? apolloContext.forwardToConfig.version : undefined), _defineProperty__default['default'](_omitEmpty, SUPPORTED_HEADERS.X_FORWARD_TO, apolloContext.forwardToConfig ? apolloContext.forwardToConfig.uri : undefined), _omitEmpty)) + }); + return forward(operation); +}); + +var tokenRetryLink = new retry.RetryLink({ + attempts: function attempts(count, operation, error) { + var context = operation.getContext(); + + if ((error === null || error === void 0 ? void 0 : error.statusCode) === constants.STATUS_CODES.UNAUTHORIZED && count === 1 && getDoesGraphQLTargetSupportTokenRetry(context) && !getSkipTokenRetry(context)) { + operation.setContext(function (_ref) { + var headers = _ref.headers; + return { + headers: forwardTokenRetryHeader(headers) + }; + }); + return true; + } + + return false; + } +}); + +// NOTE: This string will be replaced in the `prepare` script by the `scripts/version.js` file. +var version = '__@APPLICATION_KIT_PACKAGE/VERSION_OF_RELEASE__'; + +var _context; + +function ownKeys$2(object, enumerableOnly) { var keys = _Object$keys__default['default'](object); if (_Object$getOwnPropertySymbols__default['default']) { var symbols = _Object$getOwnPropertySymbols__default['default'](object); if (enumerableOnly) symbols = _filterInstanceProperty__default['default'](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default['default'](object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context4; _forEachInstanceProperty__default['default'](_context4 = ownKeys$2(Object(source), true)).call(_context4, function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors__default['default']) { _Object$defineProperties__default['default'](target, _Object$getOwnPropertyDescriptors__default['default'](source)); } else { var _context5; _forEachInstanceProperty__default['default'](_context5 = ownKeys$2(Object(source))).call(_context5, function (key) { _Object$defineProperty__default['default'](target, key, _Object$getOwnPropertyDescriptor__default['default'](source, key)); }); } } return target; } +var userAgent = createHttpUserAgent__default['default']({ + name: 'apollo-client', + // version: apolloVersion.version, + libraryName: [window.app.applicationName, 'application-shell'].join('/'), + libraryVersion: version, + contactUrl: 'https://git.io/fjuyC', + // points to the appkit repo issues + contactEmail: 'support@commercetools.com' +}); +var httpLink = client.createHttpLink({ + uri: "".concat(getMcApiUrl(), "/graphql"), + headers: { + accept: 'application/json', + 'x-user-agent': userAgent + }, + fetch: fetch +}); // order of links is relevant here +// in the request-phase they are executed top to bottom +// in the response/phase they are executed bottom to top +// `tokenRetryLink` needs to stay after `errorLink` in order to be executed before `errorLink` for responses + +var link = client.from(_concatInstanceProperty__default['default'](_context = [headerLink, errorLink]).call(_context, _toConsumableArray__default['default'](isLoggerEnabled() ? [loggerLink__default['default']] : []), [tokenRetryLink, httpLink])); // This custom merge function allows to merge two arrays of objects. +// The incoming list is what we need to update to, but we still need +// to ensure that existing cache elements are not removed but updated. +// This is usually the case when elements get removed. + +var mergeArraysObjects = function mergeArraysObjects() { + var existing = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var incoming = arguments.length > 1 ? arguments[1] : undefined; + + var _ref = arguments.length > 2 ? arguments[2] : undefined, + mergeObjects = _ref.mergeObjects; + + return _reduceInstanceProperty__default['default'](incoming).call(incoming, function (mergedElements, elem) { + var _context3; + + var existingElem = _findInstanceProperty__default['default'](existing).call(existing, function (el) { + return el.__ref === elem.__ref; + }); + + if (existingElem) { + var updatedElem = mergeObjects(existingElem, elem); + + if (updatedElem) { + var _context2; + + return _concatInstanceProperty__default['default'](_context2 = []).call(_context2, _toConsumableArray__default['default'](mergedElements), [updatedElem]); + } + } + + return _concatInstanceProperty__default['default'](_context3 = []).call(_context3, _toConsumableArray__default['default'](mergedElements), [elem]); + }, []); +}; + +var createApolloClient = function createApolloClient() { + var _options$cache, _customCacheConfig$ty; + + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var customCacheConfig = (_options$cache = options === null || options === void 0 ? void 0 : options.cache) !== null && _options$cache !== void 0 ? _options$cache : {}; + return new client.ApolloClient({ + link: link, + // https://www.apollographql.com/docs/react/caching/cache-configuration/ + cache: new client.InMemoryCache(_objectSpread$2(_objectSpread$2({}, customCacheConfig), {}, { + // https://www.apollographql.com/docs/react/caching/cache-configuration/#generating-unique-identifiers + typePolicies: _objectSpread$2({ + // CTP types with `key` as identifier + Project: { + keyFields: ['key'] + }, + Store: { + keyFields: ['key'] + }, + // Internal apps menu links representations + ApplicationsMenu: { + fields: { + appBar: { + merge: mergeArraysObjects + }, + navBar: { + merge: mergeArraysObjects + } + } + } + }, (_customCacheConfig$ty = customCacheConfig.typePolicies) !== null && _customCacheConfig$ty !== void 0 ? _customCacheConfig$ty : {}) + })) + }); +}; + +var _this = undefined, + _jsxFileName = "/Users/emmenko/projects/commercetools/merchant-center-application-kit/packages/application-shell/src/test-utils/test-utils.tsx"; + +function ownKeys$3(object, enumerableOnly) { var keys = _Object$keys__default['default'](object); if (_Object$getOwnPropertySymbols__default['default']) { var symbols = _Object$getOwnPropertySymbols__default['default'](object); if (enumerableOnly) symbols = _filterInstanceProperty__default['default'](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default['default'](object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread$3(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context14; _forEachInstanceProperty__default['default'](_context14 = ownKeys$3(Object(source), true)).call(_context14, function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors__default['default']) { _Object$defineProperties__default['default'](target, _Object$getOwnPropertyDescriptors__default['default'](source)); } else { var _context15; _forEachInstanceProperty__default['default'](_context15 = ownKeys$3(Object(source))).call(_context15, function (key) { _Object$defineProperty__default['default'](target, key, _Object$getOwnPropertyDescriptor__default['default'](source, key)); }); } } return target; } +afterEach(memoryAdapter__default['default'].reset); // These default values get merged with the values provided by the test from +// the call to "render" + +var defaultProject = { + key: 'test-with-big-data', + version: 43, + name: 'Test with big data', + countries: ['de', 'en'], + currencies: ['EUR', 'GBP'], + languages: ['de', 'en-GB', 'en'], + owner: { + id: 'organization-id-1', + name: 'Organization Name' + }, + initialized: true, + expiry: { + isActive: false, + daysLeft: undefined + }, + suspension: { + isActive: false, + reason: undefined + }, + allAppliedPermissions: [], + allAppliedActionRights: [], + allAppliedMenuVisibilities: [], + allAppliedDataFences: [] +}; +var defaultUser = { + id: 'user-id-1', + email: 'sheldon.cooper@caltech.edu', + firstName: 'Sheldon', + lastName: 'Cooper', + language: 'en', + timeZone: 'Etc/UTC', + numberFormat: 'en', + defaultProjectKey: defaultProject.key, + businessRole: 'Other', + projects: { + total: 1, + results: [defaultProject] + }, + gravatarHash: 'aaa', + launchdarklyTrackingGroup: 'commercetools', + launchdarklyTrackingSubgroup: 'dev', + launchdarklyTrackingId: '111', + launchdarklyTrackingTeam: undefined, + launchdarklyTrackingTenant: 'gcp-eu' +}; +var defaultEnvironment = { + applicationName: 'my-app', + frontendHost: 'localhost:3001', + mcApiUrl: 'https://mc-api.europe-west1.gcp.commercetools.com', + location: 'eu', + env: 'production', + cdnUrl: 'http://localhost:3001', + servedByProxy: false +}; + +var LoadingFallback = function LoadingFallback() { + return core.jsx(React__default['default'].Fragment, null, 'Loading...'); +}; + +LoadingFallback.displayName = 'LoadingFallback'; +var defaultFlopflipAdapterArgs = { + clientSideId: 'test-client-side-id', + user: { + key: 'user-key' + }, + adapterConfiguration: { + pollingInteral: 1 + }, + flags: {} +}; // For backwards compatibility we need to denormalize the given `permissions` option +// (which is now deprecated) to `allAppliedPermissions`, in order to pass the value +// to the `project` prop in the application context provider. +// From: +// { +// permissions: { +// canManageProjectSettings: true +// } +// } +// To: +// { +// allAppliedPermissions: [ +// { name: 'canManageProjectSettings', value: true } +// ] +// } + +var denormalizePermissions = function denormalizePermissions(permissions) { + var _context; + + if (!permissions) return []; + return _reduceInstanceProperty__default['default'](_context = _Object$keys__default['default'](permissions)).call(_context, function (allAppliedPermissions, permissionKey) { + var _context2; + + return _concatInstanceProperty__default['default'](_context2 = []).call(_context2, _toConsumableArray__default['default'](allAppliedPermissions), [{ + name: permissionKey, + value: permissions[permissionKey] + }]); + }, []); +}; // For backwards compatibility we need to denormalize the given `actionRights` option +// (which is now deprecated) to `allAppliedActionRights`, in order to pass the value +// to the `project` prop in the application context provider. +// From: +// { +// actionRights: { +// products: { +// canEditPrices: true, +// canPublishProducts: false, +// } +// } +// } +// To: +// { +// allAppliedActionRights: [ +// { group: 'products', name: 'canEditPrices', value: true }, +// { group: 'products', name: 'canPublishProducts', value: false } +// ] +// } + + +var denormalizeActionRights = function denormalizeActionRights(actionRights) { + var _context3; + + if (!actionRights) return []; + return _reduceInstanceProperty__default['default'](_context3 = _Object$keys__default['default'](actionRights)).call(_context3, function (allAppliedActionRights, actionRightGroup) { + var _context4, _context5; + + return _concatInstanceProperty__default['default'](_context4 = []).call(_context4, _toConsumableArray__default['default'](allAppliedActionRights), _toConsumableArray__default['default'](_reduceInstanceProperty__default['default'](_context5 = _Object$keys__default['default'](actionRights[actionRightGroup])).call(_context5, function (allActionRightsByGroup, actionRightKey) { + var _context6; + + return _concatInstanceProperty__default['default'](_context6 = []).call(_context6, _toConsumableArray__default['default'](allActionRightsByGroup), [{ + group: actionRightGroup, + name: actionRightKey, + value: actionRights[actionRightGroup][actionRightKey] + }]); + }, []))); + }, []); +}; // For backwards compatibility we need to denormalize the given `dataFences` option +// (which is now deprecated) to `allAppliedDataFences`, in order to pass the value +// to the `project` prop in the application context provider. +// From: +// { +// dataFences: { +// store: { +// orders: { +// canViewOrders: { +// values: ['store-1'], +// } +// } +// } +// } +// } +// To: +// { +// allAppliedDataFences: [ +// { type: 'store', group: 'orders', name: 'canViewOrders', value: 'store-1' } +// ] +// } + + +var denormalizeDataFences = function denormalizeDataFences(dataFences) { + var _context7; + + if (!dataFences) return []; + return _reduceInstanceProperty__default['default'](_context7 = _Object$keys__default['default'](dataFences)).call(_context7, function (allAppliedDataFences, dataFenceGroupKey) { + var _context8, _context9; + + switch (dataFenceGroupKey) { + case 'store': + return _concatInstanceProperty__default['default'](_context8 = []).call(_context8, _toConsumableArray__default['default'](allAppliedDataFences), _toConsumableArray__default['default'](_reduceInstanceProperty__default['default'](_context9 = _Object$keys__default['default'](dataFences.store)).call(_context9, function (allResources, resourceType) { + var _context10, _context11; + + return _concatInstanceProperty__default['default'](_context10 = []).call(_context10, _toConsumableArray__default['default'](allResources), _toConsumableArray__default['default'](_reduceInstanceProperty__default['default'](_context11 = _Object$keys__default['default'](dataFences.store[resourceType])).call(_context11, function (allPermissions, permissionKey) { + var _context12, _context13; + + return _concatInstanceProperty__default['default'](_context12 = []).call(_context12, _toConsumableArray__default['default'](allPermissions), _toConsumableArray__default['default'](_mapInstanceProperty__default['default'](_context13 = _valuesInstanceProperty__default['default'](dataFences.store[resourceType][permissionKey])).call(_context13, function (value) { + return { + __typename: 'StoreDataFence', + type: 'store', + value: value, + group: resourceType, + name: permissionKey + }; + }))); + }, []))); + }, []))); + + default: + return allAppliedDataFences; + } + }, []); +}; + +var wrapIfNeeded = function wrapIfNeeded(children, wrapper) { + return wrapper ? /*#__PURE__*/React__default['default'].createElement(wrapper, null, children) : children; +}; + +var ApolloProviderWrapper = function ApolloProviderWrapper(props) { + var _props$apolloClient, _apolloClient$cache$a; + + var apolloClient = (_props$apolloClient = props.apolloClient) !== null && _props$apolloClient !== void 0 ? _props$apolloClient : createApolloClient(); + + if (props.disableApolloMocks) { + return core.jsx(react.ApolloProvider, { + client: apolloClient, + __self: _this, + __source: { + fileName: _jsxFileName, + lineNumber: 277, + columnNumber: 7 + } + }, props.children); + } + + return core.jsx(testing.MockedProvider, { + mocks: props.mocks // The `addTypename` field is a private field of the cache in TS + // but we should be able to still access it. + // This is to ensure the `addTypename` behavior is the same between the + // Apollo cache and the mocked provider. + // @ts-expect-error + , + addTypename: (_apolloClient$cache$a = apolloClient.cache.addTypename) !== null && _apolloClient$cache$a !== void 0 ? _apolloClient$cache$a : true, + cache: apolloClient.cache, + __self: _this, + __source: { + fileName: _jsxFileName, + lineNumber: 281, + columnNumber: 5 + } + }, props.children); +}; // This function renders any component within the application context, as if it +// was rendered inside . +// The context is not completely set up yet, some things are missing: +// - Tracking on context +// - react-intl's information from addLocaleData +// - possibly more that I'm not aware of right now +// +// We can add these things as we go and when we need them. + + +ApolloProviderWrapper.propTypes = { + disableApolloMocks: PropTypes__default['default'].bool.isRequired, + children: PropTypes__default['default'].element.isRequired +}; + +// Inspired by +// https://github.com/kentcdodds/react-testing-library-course/blob/2a5b1560656790bb1d9c055fba3845780b2c2c97/src/__tests__/react-router-03.js +function renderApp(ui) { + var _this2 = this; + + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var _ref$locale = _ref.locale, + locale = _ref$locale === void 0 ? 'en' : _ref$locale, + _ref$mocks = _ref.mocks, + mocks = _ref$mocks === void 0 ? [] : _ref$mocks, + apolloClient = _ref.apolloClient, + _ref$disableApolloMoc = _ref.disableApolloMocks, + disableApolloMocks = _ref$disableApolloMoc === void 0 ? false : _ref$disableApolloMoc, + _ref$route = _ref.route, + route = _ref$route === void 0 ? '/' : _ref$route, + _ref$history = _ref.history, + history$2 = _ref$history === void 0 ? history.createEnhancedHistory(history$1.createMemoryHistory({ + initialEntries: [route] + })) : _ref$history, + _ref$adapter = _ref.adapter, + adapter = _ref$adapter === void 0 ? memoryAdapter__default['default'] : _ref$adapter, + _ref$flags = _flagsInstanceProperty__default['default'](_ref), + flags = _ref$flags === void 0 ? {} : _ref$flags, + environment = _ref.environment, + user = _ref.user, + project = _ref.project, + permissions = _ref.permissions, + actionRights = _ref.actionRights, + dataFences = _ref.dataFences, + _ref$dataLocale = _ref.dataLocale, + dataLocale = _ref$dataLocale === void 0 ? 'en' : _ref$dataLocale, + renderOptions = _objectWithoutProperties__default['default'](_ref, ["locale", "mocks", "apolloClient", "disableApolloMocks", "route", "history", "adapter", "flags", "environment", "user", "project", "permissions", "actionRights", "dataFences", "dataLocale"]); + + var mergedUser = user === null ? undefined : _objectSpread$3(_objectSpread$3({}, defaultUser), user); + var mergedProject = project === null ? undefined : _objectSpread$3(_objectSpread$3(_objectSpread$3({}, defaultProject), project), {}, { + allAppliedPermissions: denormalizePermissions(permissions), + allAppliedActionRights: denormalizeActionRights(actionRights), + allAppliedDataFences: denormalizeDataFences(dataFences) + }); + + var mergedEnvironment = _objectSpread$3(_objectSpread$3({}, defaultEnvironment), environment); + + var hasFlags = flags && _Object$keys__default['default'](flags).length > 0; + + var ApplicationProviders = function ApplicationProviders(props) { + return core.jsx(reactIntl.IntlProvider, { + locale: locale, + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 383, + columnNumber: 5 + } + }, core.jsx(ApolloProviderWrapper, { + disableApolloMocks: disableApolloMocks, + apolloClient: apolloClient, + mocks: mocks, + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 384, + columnNumber: 7 + } + }, core.jsx(reactBroadcast.ConfigureFlopFlip, { + adapter: adapter, + defaultFlags: flags, + adapterArgs: defaultFlopflipAdapterArgs, + shouldDeferAdapterConfiguration: !hasFlags, + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 389, + columnNumber: 9 + } + }, core.jsx(applicationShellConnectors.ApplicationContextProvider, { + user: mergedUser, + project: mergedProject, + environment: mergedEnvironment, + projectDataLocale: dataLocale, + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 395, + columnNumber: 11 + } + }, core.jsx(reactRouterDom.Router, { + history: history$2, + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 401, + columnNumber: 13 + } + }, core.jsx(React__default['default'].Suspense, { + fallback: core.jsx(LoadingFallback, { + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 402, + columnNumber: 41 + } + }), + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 402, + columnNumber: 15 + } + }, props.children)))))); + }; + + ApplicationProviders.propTypes = { + children: PropTypes__default['default'].node.isRequired + }; + var rendered = rtl.render(ui, _objectSpread$3(_objectSpread$3({}, renderOptions), {}, { + // eslint-disable-next-line react/display-name + wrapper: function wrapper(_ref2) { + var children = _ref2.children, + props = _objectWithoutProperties__default['default'](_ref2, ["children"]); + + return core.jsx(ApplicationProviders, _extends__default['default']({}, props, { + __self: _this2, + __source: { + fileName: _jsxFileName, + lineNumber: 419, + columnNumber: 7 + } + }), wrapIfNeeded(children, renderOptions.wrapper)); + } + })); + return _objectSpread$3(_objectSpread$3({}, rendered), {}, { + // adding `history` to the returned utilities to allow us + // to reference it in our tests (just try to avoid using + // this to test implementation details). + history: history$2, + // Adding user, project & environment so tests know about the merge results + // Note that these objects do not resemble the application context, they are + // only intended to communicate the test setup back to the tests. + user: mergedUser, + project: mergedProject, + environment: mergedEnvironment + }); +} + +// Test setup for rendering with Redux +// We expose a sophisticated function because we plan to get rid of Redux +// Use this function only when your test actually needs Redux +function renderAppWithRedux(ui) { + var _this3 = this; + + var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var _ref3$store = _ref3.store, + store = _ref3$store === void 0 ? undefined : _ref3$store, + _ref3$storeState = _ref3.storeState, + storeState = _ref3$storeState === void 0 ? undefined : _ref3$storeState, + _ref3$sdkMocks = _ref3.sdkMocks, + sdkMocks = _ref3$sdkMocks === void 0 ? [] : _ref3$sdkMocks, + _ref3$mapNotification = _ref3.mapNotificationToComponent, + mapNotificationToComponent = _ref3$mapNotification === void 0 ? function () { + return null; + } : _ref3$mapNotification, + renderOptions = _objectWithoutProperties__default['default'](_ref3, ["store", "storeState", "sdkMocks", "mapNotificationToComponent"]); + + invariant__default['default'](!(store && storeState), 'test-utils: You provided both `store` and `storeState`. Please provide only one of them.'); + invariant__default['default'](!(store && sdkMocks.length > 0), 'test-utils: You provided both `store` and `sdkMocks`. Please provide only one of them.'); // Determine the redux store to use in tests. + // - When the user passed in a "store", we use that store and ignore + // sdkMocks and storeState. + // - When the user passed in no sdkMocks, we create a store using the + // provided storeState. If storeState is undefined, then the defaults kick + // in anyways. + // - Lastly, when sdkMocks were provided (and no store was provided), we + // create a store which applies a special middleware to allow mocking sdk + // responses. We further initialize the store with the provided storeState. + // If storeState is undefined, then the defaults kick in anyways. + + var reduxStore = function () { + if (store) return store; + if (sdkMocks.length === 0) return createReduxStore(storeState); + var testingMiddleware = testUtils.createTestMiddleware(sdkMocks); + return createReduxStore(storeState, [testingMiddleware]); + }(); + + var ReduxProviders = function ReduxProviders(props) { + return core.jsx(reactNotifications.NotificationProviderForCustomComponent, { + mapNotificationToComponent: mapNotificationToComponent, + __self: _this3, + __source: { + fileName: _jsxFileName, + lineNumber: 534, + columnNumber: 5 + } + }, core.jsx(reactRedux.Provider, { + store: reduxStore, + __self: _this3, + __source: { + fileName: _jsxFileName, + lineNumber: 537, + columnNumber: 7 + } + }, core.jsx("div", { + __self: _this3, + __source: { + fileName: _jsxFileName, + lineNumber: 538, + columnNumber: 9 + } + }, core.jsx(reactNotifications.NotificationsList, { + domain: constants.DOMAINS.GLOBAL, + __self: _this3, + __source: { + fileName: _jsxFileName, + lineNumber: 539, + columnNumber: 11 + } + }), core.jsx(reactNotifications.NotificationsList, { + domain: constants.DOMAINS.PAGE, + __self: _this3, + __source: { + fileName: _jsxFileName, + lineNumber: 540, + columnNumber: 11 + } + }), core.jsx(reactNotifications.NotificationsList, { + domain: constants.DOMAINS.SIDE, + __self: _this3, + __source: { + fileName: _jsxFileName, + lineNumber: 541, + columnNumber: 11 + } + }), props.children))); + }; + + ReduxProviders.propTypes = { + children: PropTypes__default['default'].node.isRequired + }; + var rendered = renderApp(ui, _objectSpread$3(_objectSpread$3({}, renderOptions), {}, { + // eslint-disable-next-line react/display-name + wrapper: function wrapper(_ref4) { + var children = _ref4.children, + props = _objectWithoutProperties__default['default'](_ref4, ["children"]); + + return core.jsx(ReduxProviders, _extends__default['default']({}, props, { + __self: _this3, + __source: { + fileName: _jsxFileName, + lineNumber: 555, + columnNumber: 7 + } + }), wrapIfNeeded(children, renderOptions.wrapper)); + } + })); + return _objectSpread$3(_objectSpread$3({}, rendered), {}, { + // adding `store` to the returned utilities to allow us + // to reference it in our tests (just try to avoid using + // this to test implementation details). + store: reduxStore + }); +} // re-export everything + +Object.keys(rtl).forEach(function (k) { + if (k !== 'default') Object.defineProperty(exports, k, { + enumerable: true, + get: function () { + return rtl[k]; + } + }); +}); +exports.renderApp = renderApp; +exports.renderAppWithRedux = renderAppWithRedux; diff --git a/packages/application-shell/test-utils/package.json b/packages/application-shell/test-utils/package.json deleted file mode 100644 index 066179fe0d..0000000000 --- a/packages/application-shell/test-utils/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "main": "dist/application-shell.cjs.js", - "module": "dist/application-shell.esm.js", - "preconstruct": { - "source": "../src/test-utils" - } -} diff --git a/packages/application-shell/tsconfig.declarations.json b/packages/application-shell/tsconfig.declarations.json new file mode 100644 index 0000000000..b4b3bcc9a6 --- /dev/null +++ b/packages/application-shell/tsconfig.declarations.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { "declaration": true, "isolatedModules": false }, + "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], + "include": ["../../@types-extensions/*"] +} diff --git a/packages/application-shell/tsconfig.json b/packages/application-shell/tsconfig.json new file mode 100644 index 0000000000..a762f0bc28 --- /dev/null +++ b/packages/application-shell/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "files": ["./src/index.ts", "./src/test-utils/index.ts"] +}