@coveo/quantic 3.10.0-pre.faaf12d7a7 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -12
- package/force-app/main/default/labels/CustomLabels.labels-meta.xml +7 -0
- package/force-app/main/default/lwc/quanticCaseAssistInterface/quanticCaseAssistInterface.js +8 -0
- package/force-app/main/default/lwc/quanticCategoryFacet/__tests__/quanticCategoryFacet.test.js +108 -1
- package/force-app/main/default/lwc/quanticCategoryFacet/quanticCategoryFacet.js +22 -0
- package/force-app/main/default/lwc/quanticDateFacet/__tests__/quanticDateFacet.test.js +107 -1
- package/force-app/main/default/lwc/quanticDateFacet/quanticDateFacet.js +22 -0
- package/force-app/main/default/lwc/quanticFacet/__tests__/quanticFacet.test.js +106 -1
- package/force-app/main/default/lwc/quanticFacet/quanticFacet.js +21 -1
- package/force-app/main/default/lwc/quanticFeedbackModalQna/__tests__/quanticFeedbackModalQna.test.js +1 -1
- package/force-app/main/default/lwc/quanticFeedbackModalQna/quanticFeedbackModalQna.js +1 -1
- package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/generatedAnswer.css +0 -1
- package/force-app/main/default/lwc/quanticGeneratedAnswerContent/templates/generatedMarkdownContent.css +1 -0
- package/force-app/main/default/lwc/quanticInsightInterface/quanticInsightInterface.js +8 -0
- package/force-app/main/default/lwc/quanticNotifications/__tests__/quanticNotifications.test.js +112 -4
- package/force-app/main/default/lwc/quanticNotifications/quanticNotifications.css +8 -0
- package/force-app/main/default/lwc/quanticNotifications/quanticNotifications.html +20 -7
- package/force-app/main/default/lwc/quanticNotifications/quanticNotifications.js +57 -18
- package/force-app/main/default/lwc/quanticNumericFacet/__tests__/quanticNumericFacet.test.js +107 -1
- package/force-app/main/default/lwc/quanticNumericFacet/quanticNumericFacet.js +22 -0
- package/force-app/main/default/lwc/quanticRecommendationInterface/quanticRecommendationInterface.js +8 -0
- package/force-app/main/default/lwc/quanticSearchInterface/quanticSearchInterface.js +8 -0
- package/force-app/main/default/lwc/quanticTimeframeFacet/__tests__/quanticTimeframeFacet.test.js +107 -1
- package/force-app/main/default/lwc/quanticTimeframeFacet/quanticTimeframeFacet.js +22 -0
- package/force-app/main/default/lwc/quanticUserActionsToggle/__tests__/quanticUserActionsToggle.test.js +18 -0
- package/force-app/main/default/lwc/quanticUserActionsToggle/e2e/data.ts +32 -0
- package/force-app/main/default/lwc/quanticUserActionsToggle/e2e/fixture.ts +32 -0
- package/force-app/main/default/lwc/quanticUserActionsToggle/e2e/pageObject.ts +71 -0
- package/force-app/main/default/lwc/quanticUserActionsToggle/e2e/quanticUserActionsToggle.e2e.ts +39 -0
- package/force-app/main/default/staticresources/coveobueno/browser/bueno.js +3 -18
- package/force-app/main/default/staticresources/coveoheadless/case-assist/headless.js +9 -6
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/commerce/common/request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/commerce/recommendations/recommendations-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/commerce/search/query-suggest/query-suggest-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/knowledge/stream-answer-api.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/service/case-assist/get-case-classifications/get-case-classifications-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/service/case-assist/get-document-suggestions/get-document-suggestions-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/service/insight/get-interface/get-interface-config-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/service/insight/query/query-request.d.ts +2 -2
- package/force-app/main/default/staticresources/coveoheadless/definitions/api/service/insight/user-actions/user-actions-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-engine/commerce-engine.ssr.d.ts +4 -13
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/common.d.ts +8 -3
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/factories/build-factory.d.ts +19 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/factories/hydrated-state-factory.d.ts +4 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/factories/recommendation-hydrated-state-factory.d.ts +3 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/factories/recommendation-static-state-factory.d.ts +3 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/factories/static-state-factory.d.ts +4 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/types/build.d.ts +13 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/types/common.d.ts +180 -5
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/types/core-engine.d.ts +29 -10
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/types/fetch-static-state.d.ts +15 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/types/from-build-result.d.ts +20 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/commerce-ssr-engine/types/hydrate-static-state.d.ts +18 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/logger.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/navigatorContextProvider.d.ts +17 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/ssr-engine/types/common.d.ts +6 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/app/ssr-engine/types/from-build-result.d.ts +1 -0
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/core/parameter-manager/headless-core-parameter-manager.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/field-suggestions/headless-field-suggestions-generator.ssr.d.ts +2 -2
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/instant-products/headless-instant-products.ssr.d.ts +3 -3
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/product-view/headless-product-view.ssr.d.ts +2 -2
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/recent-queries-list/headless-recent-queries-list.ssr.d.ts +2 -2
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/recommendations/headless-recommendations.ssr.d.ts +10 -4
- package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/standalone-search-box/headless-standalone-search-box.ssr.d.ts +2 -2
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/analytics/search-action-cause.d.ts +0 -82
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/facets/facet-set/facet-set-analytics-actions.d.ts +0 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/history/history-analytics-actions.d.ts +0 -3
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/search/legacy/search-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/search/search-actions.d.ts +2 -2
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/search/search-request.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/features/static-filter-set/static-filter-set-actions.d.ts +0 -4
- package/force-app/main/default/staticresources/coveoheadless/definitions/ssr-commerce.index.d.ts +4 -4
- package/force-app/main/default/staticresources/coveoheadless/definitions/test/mock-engine-v2.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/utils/facet-utils.d.ts +1 -1
- package/force-app/main/default/staticresources/coveoheadless/definitions/utils/utils.d.ts +4 -0
- package/force-app/main/default/staticresources/coveoheadless/headless.js +11 -8
- package/force-app/main/default/staticresources/coveoheadless/insight/headless.js +10 -7
- package/force-app/main/default/staticresources/coveoheadless/recommendation/headless.js +9 -6
- package/force-app/main/default/staticresources/dompurify/purify.min.js +1339 -2
- package/package.json +23 -19
package/README.md
CHANGED
|
@@ -55,8 +55,8 @@ Or you can run the individual commands below.
|
|
|
55
55
|
- Make sure you are in the `packages/quantic` root folder.
|
|
56
56
|
- Run this command to create the default scratch org. `npm run scratch:create`.
|
|
57
57
|
- In VS Code, press Command + Shift P, enter sfdx, and select SFDX: Create a Default Scratch Org.
|
|
58
|
-
- You can also run this command from the command line. `sf org create scratch --set-default --definition-file config/
|
|
59
|
-
- `
|
|
58
|
+
- You can also run this command from the command line. `sf org create scratch --set-default --definition-file config/lws-enabled-scratch-def.json --alias Quantic__LWS_enabled`
|
|
59
|
+
- `Quantic__LWS_enabled` is an alias for the scratch org that you can use in other Salesforce CLI commands. You can create any alias that you like.
|
|
60
60
|
|
|
61
61
|
#### Deploy the Quantic code
|
|
62
62
|
|
|
@@ -64,39 +64,55 @@ Or you can run the individual commands below.
|
|
|
64
64
|
|
|
65
65
|
## Testing
|
|
66
66
|
|
|
67
|
-
### Deploy the Quantic Examples
|
|
67
|
+
### Deploy the Quantic Examples Communities
|
|
68
68
|
|
|
69
|
-
Example components are available as
|
|
69
|
+
Example components are available as Salesforce communities (Digital Experiences), allowing you to experiment with Quantic components in two separate environments: one with Lightning Web Security (LWS) enabled and one with LWS disabled.
|
|
70
70
|
|
|
71
|
-
To
|
|
71
|
+
To set up both communities in scratch orgs, run:
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
74
|
npm run setup:examples
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
This script creates, configures, and deploys everything required to have fully working examples
|
|
77
|
+
This script creates, configures, and deploys everything required to have fully working examples in **two scratch orgs**:
|
|
78
|
+
|
|
79
|
+
- An org with **LWS enabled**.
|
|
80
|
+
- An org with **LWS disabled**.
|
|
81
|
+
|
|
82
|
+
At the end of the script, the URLs for the two communities are provided, as in the following example:
|
|
78
83
|
|
|
79
84
|
```
|
|
80
|
-
...
|
|
81
85
|
|
|
82
|
-
The 'Quantic Examples' community is ready, you can access it at the following URL:
|
|
83
|
-
https://your-salesforce-scratch-org-instance.force.com/examples
|
|
86
|
+
The 'Quantic Examples' community (LWS enabled) is ready, you can access it at the following URL:
|
|
87
|
+
https://your-salesforce-lws-enabled-scratch-org-instance.force.com/examples
|
|
88
|
+
|
|
89
|
+
The 'Quantic Examples' community (LWS disabled) is ready, you can access it at the following URL:
|
|
90
|
+
https://your-salesforce-lws-disabled-scratch-org-instance.force.com/examples
|
|
84
91
|
|
|
85
92
|
To open Cypress, run:
|
|
86
93
|
npm run e2e:watch
|
|
87
94
|
```
|
|
88
95
|
|
|
89
|
-
Once the community has been deployed, you can deploy the `main` or `example` components only when needed
|
|
96
|
+
Once the community has been deployed, you can deploy the `main` or `example` components to a specific org only when needed by running the corresponding commands:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm run deploy:main --target-org Quantic__LWS_enabled
|
|
100
|
+
npm run deploy:examples --target-org Quantic__LWS_enabled
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
You can replace Quantic\_\_LWS_enabled with your target org alias. For example:
|
|
90
104
|
|
|
91
105
|
```bash
|
|
92
|
-
npm run deploy:main
|
|
93
|
-
npm run deploy:examples
|
|
106
|
+
npm run deploy:main --target-org MyCustomOrg
|
|
107
|
+
npm run deploy:examples --target-org MyCustomOrg
|
|
94
108
|
```
|
|
95
109
|
|
|
96
110
|
### Run Cypress for Quantic Components
|
|
97
111
|
|
|
98
112
|
**Note** Before attempting to run [Cypress](https://docs.cypress.io) tests, make sure the `Quantic Examples` community is deployed as described in the previous section.
|
|
99
113
|
|
|
114
|
+
**Note** Cypress tests run on the org with **LWS enabled**, aliased as `Quantic__LWS_enabled`.
|
|
115
|
+
|
|
100
116
|
To learn how to add tests, see [adding tests](./docs/adding-tests.md).
|
|
101
117
|
|
|
102
118
|
- All the tests will need to be under folder `cypress/integration`.
|
|
@@ -119,6 +135,30 @@ To get the [detailed report](./docs/detailed-reporting.md), run:
|
|
|
119
135
|
npm run e2e:detailed
|
|
120
136
|
```
|
|
121
137
|
|
|
138
|
+
### Run Playwright for Quantic Components
|
|
139
|
+
|
|
140
|
+
**Note** Before attempting to run [Playwright](https://playwright.dev/) tests, make sure the `Quantic Examples` community is deployed as described in the previous section in both orgs, the one where LWS is enabled and the one where it is disabled.
|
|
141
|
+
|
|
142
|
+
**Note** For more information on how to add tests, please refer to our [Quantic Testing Strategy](https://github.com/coveo/ui-kit/blob/master/packages/quantic/decisions/0001-testing-strategy.md), which provides detailed guidelines on testing Quantic components.
|
|
143
|
+
|
|
144
|
+
To run Playwright tests, run:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npm run e2e:playwright:
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
To run Playwright tests only for the scratch org where LWS is enabled, run:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm run e2e:playwright:lws-enabled
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
To run Playwright tests only for the scratch org where LWS is disabled, run:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm run e2e:playwright:lws-disabled
|
|
160
|
+
```
|
|
161
|
+
|
|
122
162
|
### Run LWC unit tests for Quantic Components
|
|
123
163
|
|
|
124
164
|
To run LWC unit tests directly in your console, run:
|
|
@@ -1603,4 +1603,11 @@
|
|
|
1603
1603
|
<protected>false</protected>
|
|
1604
1604
|
<shortDescription>User actions</shortDescription>
|
|
1605
1605
|
</labels>
|
|
1606
|
+
<labels>
|
|
1607
|
+
<fullName>quantic_CloseNotification</fullName>
|
|
1608
|
+
<value>Close notification</value>
|
|
1609
|
+
<language>en_US</language>
|
|
1610
|
+
<protected>false</protected>
|
|
1611
|
+
<shortDescription>Close notification</shortDescription>
|
|
1612
|
+
</labels>
|
|
1606
1613
|
</CustomLabels>
|
|
@@ -64,6 +64,14 @@ export default class QuanticCaseAssistInterface extends LightningElement {
|
|
|
64
64
|
...(document.referrer && {
|
|
65
65
|
originLevel3: document.referrer.substring(0, 256),
|
|
66
66
|
}),
|
|
67
|
+
analyticsClientMiddleware: (_event, payload) => {
|
|
68
|
+
if (!payload.customData) {
|
|
69
|
+
payload.customData = {};
|
|
70
|
+
}
|
|
71
|
+
payload.customData.coveoQuanticVersion =
|
|
72
|
+
window.coveoQuanticVersion;
|
|
73
|
+
return payload;
|
|
74
|
+
},
|
|
67
75
|
},
|
|
68
76
|
...rest,
|
|
69
77
|
},
|
package/force-app/main/default/lwc/quanticCategoryFacet/__tests__/quanticCategoryFacet.test.js
CHANGED
|
@@ -15,16 +15,21 @@ jest.mock('c/quanticUtils', () => ({
|
|
|
15
15
|
CATEGORYFACETS: 'categoryFacets',
|
|
16
16
|
},
|
|
17
17
|
},
|
|
18
|
+
I18nUtils: {
|
|
19
|
+
format: jest.fn(),
|
|
20
|
+
},
|
|
18
21
|
}));
|
|
19
22
|
jest.mock('c/quanticHeadlessLoader');
|
|
20
23
|
|
|
21
24
|
const selectors = {
|
|
22
25
|
facetContent: '[data-test="facet-content"]',
|
|
26
|
+
componentError: 'c-quantic-component-error',
|
|
23
27
|
};
|
|
24
28
|
|
|
25
29
|
const exampleFacetId = 'example facet id';
|
|
30
|
+
const exampleField = 'exampleField';
|
|
26
31
|
const defaultOptions = {
|
|
27
|
-
field:
|
|
32
|
+
field: exampleField,
|
|
28
33
|
};
|
|
29
34
|
const categoryFacetControllerMock = {
|
|
30
35
|
subscribe: jest.fn((callback) => callback()),
|
|
@@ -33,6 +38,8 @@ const categoryFacetControllerMock = {
|
|
|
33
38
|
values: [],
|
|
34
39
|
},
|
|
35
40
|
};
|
|
41
|
+
const parentFacetIdError = `The ${exampleField} c-quantic-category-facet requires dependsOn.parentFacetId to be a valid string.`;
|
|
42
|
+
const expectedValueError = `The ${exampleField} c-quantic-category-facet requires dependsOn.expectedValue to be a valid string.`;
|
|
36
43
|
|
|
37
44
|
function createTestComponent(options = defaultOptions) {
|
|
38
45
|
prepareHeadlessState();
|
|
@@ -82,6 +89,21 @@ const exampleEngine = {
|
|
|
82
89
|
};
|
|
83
90
|
let isInitialized = false;
|
|
84
91
|
|
|
92
|
+
function mockBueno() {
|
|
93
|
+
// @ts-ignore
|
|
94
|
+
mockHeadlessLoader.getBueno = () => {
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
global.Bueno = {
|
|
97
|
+
isString: jest
|
|
98
|
+
.fn()
|
|
99
|
+
.mockImplementation(
|
|
100
|
+
(value) => Object.prototype.toString.call(value) === '[object String]'
|
|
101
|
+
),
|
|
102
|
+
};
|
|
103
|
+
return new Promise((resolve) => resolve());
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
85
107
|
function mockSuccessfulHeadlessInitialization() {
|
|
86
108
|
// @ts-ignore
|
|
87
109
|
mockHeadlessLoader.initializeWithHeadless = (element, _, initialize) => {
|
|
@@ -104,6 +126,7 @@ function cleanup() {
|
|
|
104
126
|
describe('c-quantic-category-facet', () => {
|
|
105
127
|
beforeAll(() => {
|
|
106
128
|
mockSuccessfulHeadlessInitialization();
|
|
129
|
+
mockBueno();
|
|
107
130
|
});
|
|
108
131
|
|
|
109
132
|
afterEach(() => {
|
|
@@ -198,6 +221,90 @@ describe('c-quantic-category-facet', () => {
|
|
|
198
221
|
});
|
|
199
222
|
});
|
|
200
223
|
|
|
224
|
+
describe('validation of the dependsOn property', () => {
|
|
225
|
+
let consoleError;
|
|
226
|
+
beforeAll(() => {
|
|
227
|
+
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe('when dependsOn.parentFacetId is not provided', () => {
|
|
231
|
+
it('should display the error component', async () => {
|
|
232
|
+
const invalidFacetDependency = {
|
|
233
|
+
expectedValue: 'txt',
|
|
234
|
+
};
|
|
235
|
+
const element = createTestComponent({
|
|
236
|
+
...defaultOptions,
|
|
237
|
+
dependsOn: invalidFacetDependency,
|
|
238
|
+
});
|
|
239
|
+
await flushPromises();
|
|
240
|
+
|
|
241
|
+
const componentError = element.shadowRoot.querySelector(
|
|
242
|
+
selectors.componentError
|
|
243
|
+
);
|
|
244
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
245
|
+
selectors.facetContent
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
249
|
+
expect(consoleError).toHaveBeenCalledWith(parentFacetIdError);
|
|
250
|
+
expect(componentError).not.toBeNull();
|
|
251
|
+
expect(facetContent).toBeNull();
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe('when dependsOn.parentFacetId is not a string', () => {
|
|
256
|
+
it('should display the error component', async () => {
|
|
257
|
+
const invalidFacetDependency = {
|
|
258
|
+
parentFacetId: 1,
|
|
259
|
+
expectedValue: 'txt',
|
|
260
|
+
};
|
|
261
|
+
const element = createTestComponent({
|
|
262
|
+
...defaultOptions,
|
|
263
|
+
dependsOn: invalidFacetDependency,
|
|
264
|
+
});
|
|
265
|
+
await flushPromises();
|
|
266
|
+
|
|
267
|
+
const componentError = element.shadowRoot.querySelector(
|
|
268
|
+
selectors.componentError
|
|
269
|
+
);
|
|
270
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
271
|
+
selectors.facetContent
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
275
|
+
expect(consoleError).toHaveBeenCalledWith(parentFacetIdError);
|
|
276
|
+
expect(componentError).not.toBeNull();
|
|
277
|
+
expect(facetContent).toBeNull();
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
describe('when dependsOn.expectedValue is not a string', () => {
|
|
282
|
+
it('should display the error component', async () => {
|
|
283
|
+
const invalidFacetDependency = {
|
|
284
|
+
parentFacetId: 'filetype',
|
|
285
|
+
expectedValue: 2,
|
|
286
|
+
};
|
|
287
|
+
const element = createTestComponent({
|
|
288
|
+
...defaultOptions,
|
|
289
|
+
dependsOn: invalidFacetDependency,
|
|
290
|
+
});
|
|
291
|
+
await flushPromises();
|
|
292
|
+
|
|
293
|
+
const componentError = element.shadowRoot.querySelector(
|
|
294
|
+
selectors.componentError
|
|
295
|
+
);
|
|
296
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
297
|
+
selectors.facetContent
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
301
|
+
expect(consoleError).toHaveBeenCalledWith(expectedValueError);
|
|
302
|
+
expect(componentError).not.toBeNull();
|
|
303
|
+
expect(facetContent).toBeNull();
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
201
308
|
describe('when the component is disconnected', () => {
|
|
202
309
|
it('should make the condition manager stop watching the facet', async () => {
|
|
203
310
|
const exampleFacetDependency = {
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
initializeWithHeadless,
|
|
15
15
|
registerToStore,
|
|
16
16
|
getHeadlessBundle,
|
|
17
|
+
getBueno,
|
|
17
18
|
} from 'c/quanticHeadlessLoader';
|
|
18
19
|
import {
|
|
19
20
|
I18nUtils,
|
|
@@ -301,6 +302,7 @@ export default class QuanticCategoryFacet extends LightningElement {
|
|
|
301
302
|
},
|
|
302
303
|
});
|
|
303
304
|
if (this.dependsOn) {
|
|
305
|
+
this.validateDependsOnProperty();
|
|
304
306
|
this.initFacetConditionManager(engine);
|
|
305
307
|
}
|
|
306
308
|
this.unsubscribe = this.facet.subscribe(() => this.updateState());
|
|
@@ -330,6 +332,26 @@ export default class QuanticCategoryFacet extends LightningElement {
|
|
|
330
332
|
this.dispatchEvent(renderFacetEvent);
|
|
331
333
|
}
|
|
332
334
|
|
|
335
|
+
validateDependsOnProperty() {
|
|
336
|
+
if (this.dependsOn) {
|
|
337
|
+
getBueno(this).then(() => {
|
|
338
|
+
const {parentFacetId, expectedValue} = this.dependsOn;
|
|
339
|
+
if (!Bueno.isString(parentFacetId)) {
|
|
340
|
+
console.error(
|
|
341
|
+
`The ${this.field} ${this.template.host.localName} requires dependsOn.parentFacetId to be a valid string.`
|
|
342
|
+
);
|
|
343
|
+
this.setInitializationError();
|
|
344
|
+
}
|
|
345
|
+
if (expectedValue && !Bueno.isString(expectedValue)) {
|
|
346
|
+
console.error(
|
|
347
|
+
`The ${this.field} ${this.template.host.localName} requires dependsOn.expectedValue to be a valid string.`
|
|
348
|
+
);
|
|
349
|
+
this.setInitializationError();
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
333
355
|
initFacetConditionManager(engine) {
|
|
334
356
|
this.categoryFacetConditionsManager =
|
|
335
357
|
this.headless.buildFacetConditionsManager(engine, {
|
|
@@ -12,16 +12,21 @@ jest.mock('c/quanticUtils', () => ({
|
|
|
12
12
|
DATEFACETS: 'dateFacets',
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
|
+
I18nUtils: {
|
|
16
|
+
format: jest.fn(),
|
|
17
|
+
},
|
|
15
18
|
}));
|
|
16
19
|
jest.mock('c/quanticHeadlessLoader');
|
|
17
20
|
|
|
18
21
|
const selectors = {
|
|
19
22
|
facetContent: '[data-test="facet-content"]',
|
|
23
|
+
componentError: 'c-quantic-component-error',
|
|
20
24
|
};
|
|
21
25
|
|
|
22
26
|
const exampleFacetId = 'example facet id';
|
|
27
|
+
const exampleField = 'exampleField';
|
|
23
28
|
const defaultOptions = {
|
|
24
|
-
field:
|
|
29
|
+
field: exampleField,
|
|
25
30
|
};
|
|
26
31
|
const dateFacetControllerMock = {
|
|
27
32
|
subscribe: jest.fn((callback) => callback()),
|
|
@@ -30,6 +35,8 @@ const dateFacetControllerMock = {
|
|
|
30
35
|
values: [],
|
|
31
36
|
},
|
|
32
37
|
};
|
|
38
|
+
const parentFacetIdError = `The ${exampleField} c-quantic-date-facet requires dependsOn.parentFacetId to be a valid string.`;
|
|
39
|
+
const expectedValueError = `The ${exampleField} c-quantic-date-facet requires dependsOn.expectedValue to be a valid string.`;
|
|
33
40
|
|
|
34
41
|
function createTestComponent(options = defaultOptions) {
|
|
35
42
|
prepareHeadlessState();
|
|
@@ -79,6 +86,21 @@ const exampleEngine = {
|
|
|
79
86
|
};
|
|
80
87
|
let isInitialized = false;
|
|
81
88
|
|
|
89
|
+
function mockBueno() {
|
|
90
|
+
// @ts-ignore
|
|
91
|
+
mockHeadlessLoader.getBueno = () => {
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
global.Bueno = {
|
|
94
|
+
isString: jest
|
|
95
|
+
.fn()
|
|
96
|
+
.mockImplementation(
|
|
97
|
+
(value) => Object.prototype.toString.call(value) === '[object String]'
|
|
98
|
+
),
|
|
99
|
+
};
|
|
100
|
+
return new Promise((resolve) => resolve());
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
82
104
|
function mockSuccessfulHeadlessInitialization() {
|
|
83
105
|
// @ts-ignore
|
|
84
106
|
mockHeadlessLoader.initializeWithHeadless = (element, _, initialize) => {
|
|
@@ -101,6 +123,7 @@ function cleanup() {
|
|
|
101
123
|
describe('c-quantic-date-facet', () => {
|
|
102
124
|
beforeAll(() => {
|
|
103
125
|
mockSuccessfulHeadlessInitialization();
|
|
126
|
+
mockBueno();
|
|
104
127
|
});
|
|
105
128
|
|
|
106
129
|
afterEach(() => {
|
|
@@ -193,6 +216,89 @@ describe('c-quantic-date-facet', () => {
|
|
|
193
216
|
});
|
|
194
217
|
});
|
|
195
218
|
|
|
219
|
+
describe('validation of the dependsOn property', () => {
|
|
220
|
+
let consoleError;
|
|
221
|
+
beforeAll(() => {
|
|
222
|
+
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
223
|
+
});
|
|
224
|
+
describe('when dependsOn.parentFacetId is not provided', () => {
|
|
225
|
+
it('should display the error component', async () => {
|
|
226
|
+
const invalidFacetDependency = {
|
|
227
|
+
expectedValue: 'txt',
|
|
228
|
+
};
|
|
229
|
+
const element = createTestComponent({
|
|
230
|
+
...defaultOptions,
|
|
231
|
+
dependsOn: invalidFacetDependency,
|
|
232
|
+
});
|
|
233
|
+
await flushPromises();
|
|
234
|
+
|
|
235
|
+
const componentError = element.shadowRoot.querySelector(
|
|
236
|
+
selectors.componentError
|
|
237
|
+
);
|
|
238
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
239
|
+
selectors.facetContent
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
243
|
+
expect(consoleError).toHaveBeenCalledWith(parentFacetIdError);
|
|
244
|
+
expect(componentError).not.toBeNull();
|
|
245
|
+
expect(facetContent).toBeNull();
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
describe('when dependsOn.parentFacetId is not a string', () => {
|
|
250
|
+
it('should display the error component', async () => {
|
|
251
|
+
const invalidFacetDependency = {
|
|
252
|
+
parentFacetId: 1,
|
|
253
|
+
expectedValue: 'txt',
|
|
254
|
+
};
|
|
255
|
+
const element = createTestComponent({
|
|
256
|
+
...defaultOptions,
|
|
257
|
+
dependsOn: invalidFacetDependency,
|
|
258
|
+
});
|
|
259
|
+
await flushPromises();
|
|
260
|
+
|
|
261
|
+
const componentError = element.shadowRoot.querySelector(
|
|
262
|
+
selectors.componentError
|
|
263
|
+
);
|
|
264
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
265
|
+
selectors.facetContent
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
269
|
+
expect(consoleError).toHaveBeenCalledWith(parentFacetIdError);
|
|
270
|
+
expect(componentError).not.toBeNull();
|
|
271
|
+
expect(facetContent).toBeNull();
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe('when dependsOn.expectedValue is not a string', () => {
|
|
276
|
+
it('should display the error component', async () => {
|
|
277
|
+
const invalidFacetDependency = {
|
|
278
|
+
parentFacetId: 'filetype',
|
|
279
|
+
expectedValue: 2,
|
|
280
|
+
};
|
|
281
|
+
const element = createTestComponent({
|
|
282
|
+
...defaultOptions,
|
|
283
|
+
dependsOn: invalidFacetDependency,
|
|
284
|
+
});
|
|
285
|
+
await flushPromises();
|
|
286
|
+
|
|
287
|
+
const componentError = element.shadowRoot.querySelector(
|
|
288
|
+
selectors.componentError
|
|
289
|
+
);
|
|
290
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
291
|
+
selectors.facetContent
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
295
|
+
expect(consoleError).toHaveBeenCalledWith(expectedValueError);
|
|
296
|
+
expect(componentError).not.toBeNull();
|
|
297
|
+
expect(facetContent).toBeNull();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
196
302
|
describe('when the component is disconnected', () => {
|
|
197
303
|
it('should make the condition manager stop watching the facet', async () => {
|
|
198
304
|
const exampleFacetDependency = {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
initializeWithHeadless,
|
|
10
10
|
registerToStore,
|
|
11
11
|
getHeadlessBundle,
|
|
12
|
+
getBueno,
|
|
12
13
|
} from 'c/quanticHeadlessLoader';
|
|
13
14
|
import {
|
|
14
15
|
I18nUtils,
|
|
@@ -210,6 +211,7 @@ export default class QuanticDateFacet extends LightningElement {
|
|
|
210
211
|
element: this.template.host,
|
|
211
212
|
});
|
|
212
213
|
if (this.dependsOn) {
|
|
214
|
+
this.validateDependsOnProperty();
|
|
213
215
|
this.initFacetConditionManager(engine);
|
|
214
216
|
}
|
|
215
217
|
};
|
|
@@ -238,6 +240,26 @@ export default class QuanticDateFacet extends LightningElement {
|
|
|
238
240
|
this.dispatchEvent(renderFacetEvent);
|
|
239
241
|
}
|
|
240
242
|
|
|
243
|
+
validateDependsOnProperty() {
|
|
244
|
+
if (this.dependsOn) {
|
|
245
|
+
getBueno(this).then(() => {
|
|
246
|
+
const {parentFacetId, expectedValue} = this.dependsOn;
|
|
247
|
+
if (!Bueno.isString(parentFacetId)) {
|
|
248
|
+
console.error(
|
|
249
|
+
`The ${this.field} ${this.template.host.localName} requires dependsOn.parentFacetId to be a valid string.`
|
|
250
|
+
);
|
|
251
|
+
this.setInitializationError();
|
|
252
|
+
}
|
|
253
|
+
if (expectedValue && !Bueno.isString(expectedValue)) {
|
|
254
|
+
console.error(
|
|
255
|
+
`The ${this.field} ${this.template.host.localName} requires dependsOn.expectedValue to be a valid string.`
|
|
256
|
+
);
|
|
257
|
+
this.setInitializationError();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
241
263
|
initFacetConditionManager(engine) {
|
|
242
264
|
this.dateFacetConditionsManager = this.headless.buildFacetConditionsManager(
|
|
243
265
|
engine,
|
|
@@ -12,16 +12,21 @@ jest.mock('c/quanticUtils', () => ({
|
|
|
12
12
|
FACETS: 'facets',
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
|
+
I18nUtils: {
|
|
16
|
+
format: jest.fn(),
|
|
17
|
+
},
|
|
15
18
|
}));
|
|
16
19
|
jest.mock('c/quanticHeadlessLoader');
|
|
17
20
|
|
|
18
21
|
const selectors = {
|
|
19
22
|
facetContent: '[data-test="facet-content"]',
|
|
23
|
+
componentError: 'c-quantic-component-error',
|
|
20
24
|
};
|
|
21
25
|
|
|
22
26
|
const exampleFacetId = 'example facet id';
|
|
27
|
+
const exampleField = 'exampleField';
|
|
23
28
|
const defaultOptions = {
|
|
24
|
-
field:
|
|
29
|
+
field: exampleField,
|
|
25
30
|
};
|
|
26
31
|
const facetControllerMock = {
|
|
27
32
|
subscribe: jest.fn((callback) => callback()),
|
|
@@ -30,6 +35,8 @@ const facetControllerMock = {
|
|
|
30
35
|
values: [],
|
|
31
36
|
},
|
|
32
37
|
};
|
|
38
|
+
const parentFacetIdError = `The ${exampleField} c-quantic-facet requires dependsOn.parentFacetId to be a valid string.`;
|
|
39
|
+
const expectedValueError = `The ${exampleField} c-quantic-facet requires dependsOn.expectedValue to be a valid string.`;
|
|
33
40
|
|
|
34
41
|
function createTestComponent(options = defaultOptions) {
|
|
35
42
|
prepareHeadlessState();
|
|
@@ -89,6 +96,21 @@ function mockSuccessfulHeadlessInitialization() {
|
|
|
89
96
|
};
|
|
90
97
|
}
|
|
91
98
|
|
|
99
|
+
function mockBueno() {
|
|
100
|
+
// @ts-ignore
|
|
101
|
+
mockHeadlessLoader.getBueno = () => {
|
|
102
|
+
// @ts-ignore
|
|
103
|
+
global.Bueno = {
|
|
104
|
+
isString: jest
|
|
105
|
+
.fn()
|
|
106
|
+
.mockImplementation(
|
|
107
|
+
(value) => Object.prototype.toString.call(value) === '[object String]'
|
|
108
|
+
),
|
|
109
|
+
};
|
|
110
|
+
return new Promise((resolve) => resolve());
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
92
114
|
function cleanup() {
|
|
93
115
|
// The jsdom instance is shared across test cases in a single file so reset the DOM
|
|
94
116
|
while (document.body.firstChild) {
|
|
@@ -101,6 +123,7 @@ function cleanup() {
|
|
|
101
123
|
describe('c-quantic-facet', () => {
|
|
102
124
|
beforeAll(() => {
|
|
103
125
|
mockSuccessfulHeadlessInitialization();
|
|
126
|
+
mockBueno();
|
|
104
127
|
});
|
|
105
128
|
|
|
106
129
|
afterEach(() => {
|
|
@@ -214,6 +237,88 @@ describe('c-quantic-facet', () => {
|
|
|
214
237
|
});
|
|
215
238
|
});
|
|
216
239
|
|
|
240
|
+
describe('validation of the dependsOn property', () => {
|
|
241
|
+
let consoleError;
|
|
242
|
+
beforeAll(() => {
|
|
243
|
+
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
244
|
+
});
|
|
245
|
+
describe('when dependsOn.parentFacetId is not provided', () => {
|
|
246
|
+
it('should display the error component', async () => {
|
|
247
|
+
const invalidFacetDependency = {
|
|
248
|
+
expectedValue: 'txt',
|
|
249
|
+
};
|
|
250
|
+
const element = createTestComponent({
|
|
251
|
+
...defaultOptions,
|
|
252
|
+
dependsOn: invalidFacetDependency,
|
|
253
|
+
});
|
|
254
|
+
await flushPromises();
|
|
255
|
+
|
|
256
|
+
const componentError = element.shadowRoot.querySelector(
|
|
257
|
+
selectors.componentError
|
|
258
|
+
);
|
|
259
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
260
|
+
selectors.facetContent
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
264
|
+
expect(consoleError).toHaveBeenCalledWith(parentFacetIdError);
|
|
265
|
+
expect(componentError).not.toBeNull();
|
|
266
|
+
expect(facetContent).toBeNull();
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
describe('when dependsOn.parentFacetId is not a string', () => {
|
|
271
|
+
it('should display the error component', async () => {
|
|
272
|
+
const invalidFacetDependency = {
|
|
273
|
+
parentFacetId: 1,
|
|
274
|
+
expectedValue: 'txt',
|
|
275
|
+
};
|
|
276
|
+
const element = createTestComponent({
|
|
277
|
+
...defaultOptions,
|
|
278
|
+
dependsOn: invalidFacetDependency,
|
|
279
|
+
});
|
|
280
|
+
await flushPromises();
|
|
281
|
+
|
|
282
|
+
const componentError = element.shadowRoot.querySelector(
|
|
283
|
+
selectors.componentError
|
|
284
|
+
);
|
|
285
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
286
|
+
selectors.facetContent
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
290
|
+
expect(consoleError).toHaveBeenCalledWith(parentFacetIdError);
|
|
291
|
+
expect(componentError).not.toBeNull();
|
|
292
|
+
expect(facetContent).toBeNull();
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('when dependsOn.expectedValue is not a string', () => {
|
|
297
|
+
it('should display the error component', async () => {
|
|
298
|
+
const invalidFacetDependency = {
|
|
299
|
+
parentFacetId: 'filetype',
|
|
300
|
+
expectedValue: 2,
|
|
301
|
+
};
|
|
302
|
+
const element = createTestComponent({
|
|
303
|
+
...defaultOptions,
|
|
304
|
+
dependsOn: invalidFacetDependency,
|
|
305
|
+
});
|
|
306
|
+
await flushPromises();
|
|
307
|
+
|
|
308
|
+
const componentError = element.shadowRoot.querySelector(
|
|
309
|
+
selectors.componentError
|
|
310
|
+
);
|
|
311
|
+
const facetContent = element.shadowRoot.querySelector(
|
|
312
|
+
selectors.facetContent
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
expect(consoleError).toHaveBeenCalledTimes(1);
|
|
316
|
+
expect(consoleError).toHaveBeenCalledWith(expectedValueError);
|
|
317
|
+
expect(componentError).not.toBeNull();
|
|
318
|
+
expect(facetContent).toBeNull();
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
});
|
|
217
322
|
describe('when the component is disconnected', () => {
|
|
218
323
|
it('should make the condition manager stop watching the facet', async () => {
|
|
219
324
|
const exampleFacetDependency = {
|