@eeacms/volto-cca-policy 1.0.2 → 1.0.4
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/CHANGELOG.md +259 -3
- package/jest-addon.config.js +4 -2
- package/locales/bg/LC_MESSAGES/volto.po +576 -0
- package/locales/cs/LC_MESSAGES/volto.po +576 -0
- package/locales/da/LC_MESSAGES/volto.po +576 -0
- package/locales/de/LC_MESSAGES/volto.po +576 -0
- package/locales/el/LC_MESSAGES/volto.po +576 -0
- package/locales/en/LC_MESSAGES/volto.po +576 -0
- package/locales/es/LC_MESSAGES/volto.po +576 -0
- package/locales/et/LC_MESSAGES/volto.po +576 -0
- package/locales/fi/LC_MESSAGES/volto.po +576 -0
- package/locales/fr/LC_MESSAGES/volto.po +576 -0
- package/locales/ga/LC_MESSAGES/volto.po +576 -0
- package/locales/hr/LC_MESSAGES/volto.po +576 -0
- package/locales/hu/LC_MESSAGES/volto.po +576 -0
- package/locales/is/LC_MESSAGES/volto.po +576 -0
- package/locales/it/LC_MESSAGES/volto.po +576 -0
- package/locales/lt/LC_MESSAGES/volto.po +576 -0
- package/locales/lv/LC_MESSAGES/volto.po +576 -0
- package/locales/mt/LC_MESSAGES/volto.po +576 -0
- package/locales/nl/LC_MESSAGES/volto.po +576 -0
- package/locales/nn/LC_MESSAGES/volto.po +576 -0
- package/locales/pl/LC_MESSAGES/volto.po +576 -0
- package/locales/pt/LC_MESSAGES/volto.po +576 -0
- package/locales/ro/LC_MESSAGES/volto.po +576 -0
- package/locales/sk/LC_MESSAGES/volto.po +576 -0
- package/locales/sl/LC_MESSAGES/volto.po +576 -0
- package/locales/sv/LC_MESSAGES/volto.po +576 -0
- package/locales/tr/LC_MESSAGES/volto.po +576 -0
- package/locales/volto.pot +577 -1
- package/package.json +1 -1
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.jsx +224 -0
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.test.jsx +173 -0
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueContentView.jsx +189 -0
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueMapView.jsx +272 -0
- package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueMapView.test.jsx +160 -0
- package/src/components/Search/NavigatorCatalogue/utils.js +157 -0
- package/src/components/Search/NavigatorCatalogue/utils.test.js +132 -0
- package/src/components/Search/NavigatorGuide/NavigatorGuideContentView.jsx +409 -0
- package/src/components/Search/NavigatorGuide/NavigatorGuideLayout.jsx +8 -0
- package/src/components/index.js +2 -0
- package/src/components/theme/CompareTools/CompareToolsPanel.jsx +151 -0
- package/src/components/theme/CompareTools/CompareToolsPanel.test.jsx +96 -0
- package/src/components/theme/CompareTools/CompareToolsView.jsx +475 -0
- package/src/components/theme/CompareTools/CompareToolsView.test.jsx +110 -0
- package/src/components/theme/CompareTools/utils.js +111 -0
- package/src/components/theme/CompareTools/utils.test.jsx +217 -0
- package/src/components/theme/Views/ExtendedToolView.jsx +201 -201
- package/src/components/theme/Views/ExtendedToolView.test.jsx +420 -58
- package/src/constants.js +0 -48
- package/src/customizations/volto/reducers/breadcrumbs/breadcrumbs.js +1 -1
- package/src/helpers/Utils.jsx +29 -0
- package/src/helpers/index.js +3 -0
- package/src/index.js +28 -2
- package/src/search/index.js +6 -0
- package/src/search/navigator_catalogue/config.js +89 -0
- package/src/search/navigator_catalogue/facets.js +86 -0
- package/src/search/navigator_catalogue/views.js +28 -0
- package/src/search/navigator_guide/config.js +70 -0
- package/src/search/navigator_guide/facets.js +31 -0
- package/src/search/navigator_guide/guideSteps.js +93 -0
- package/src/slate-styles.less +4 -0
- package/src/state.js +1 -0
- package/theme/elements/button.overrides +0 -11
- package/theme/elements/label.overrides +15 -0
- package/theme/globals/blocks.less +3 -2
- package/theme/globals/navigator.less +1090 -0
- package/theme/globals/site.overrides +5 -0
- package/theme/tokens/colors.less +2 -0
- package/artifacts/BLOCKS.md +0 -167
- package/artifacts/link-integrity-workflow/README.md +0 -76
- package/artifacts/link-integrity-workflow/index.md +0 -33
- package/artifacts/link-integrity-workflow/link-integrity-block-fields-report.md +0 -132
- package/artifacts/link-integrity-workflow/link-integrity-blocks-report.md +0 -52
- package/artifacts/link-integrity-workflow/understanding-link-integrity.md +0 -143
- package/artifacts/link-integrity-workflow/volto-block-link-analysis.md +0 -63
- package/artifacts/link-integrity-workflow/volto-block-link-discovery.md +0 -60
- package/artifacts/test-fixes/test-fixes-specification.md +0 -267
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# Volto Block Link Discovery Analysis - volto-cca-policy
|
|
2
|
-
|
|
3
|
-
This document analyzes the custom blocks defined in the `volto-cca-policy` add-on to identify which fields contain internal links and whether they are covered by the standard Plone/Volto link integrity discovery mechanism.
|
|
4
|
-
|
|
5
|
-
## Standard Discovery Mechanism Recap
|
|
6
|
-
|
|
7
|
-
As documented in `volto-block-link-discovery.md`, the `GenericBlockLinksRetriever` automatically extracts internal links from the following top-level fields:
|
|
8
|
-
- `url`
|
|
9
|
-
- `href`
|
|
10
|
-
- `preview_image`
|
|
11
|
-
|
|
12
|
-
Any field not named exactly like one of these, or any link nested within a list or dictionary (unless it's a `blocks` container), requires a specialized retriever on the backend.
|
|
13
|
-
|
|
14
|
-
## Analysis of volto-cca-policy Blocks
|
|
15
|
-
|
|
16
|
-
### 1. Blocks Covered by Generic Retriever
|
|
17
|
-
The following blocks use standard field names at the top level and should be automatically tracked.
|
|
18
|
-
|
|
19
|
-
| Block | Field | Description |
|
|
20
|
-
|---|---|---|
|
|
21
|
-
| `RedirectBlock` | `href` | The target object for the redirection. |
|
|
22
|
-
| `CountryMapObservatory` | `href` | The parent location of all country profiles. |
|
|
23
|
-
| `CollectionStatistics` | `href` | The destination listing page. |
|
|
24
|
-
| `ASTNavigation` | `href` | The main entry page to AST/UAST (top-level). |
|
|
25
|
-
|
|
26
|
-
### 2. Blocks NOT Covered (Custom Field Names)
|
|
27
|
-
The following blocks use field names that are not recognized by the generic retriever.
|
|
28
|
-
|
|
29
|
-
| Block | Field | Description |
|
|
30
|
-
|---|---|---|
|
|
31
|
-
| `Listing` (Shadowed) | `linkTo` | Standard Volto listing block uses `linkTo` for the "More..." link. |
|
|
32
|
-
|
|
33
|
-
### 3. Blocks NOT Covered (Nested Links)
|
|
34
|
-
The following blocks store links within an `object_list`. The generic retriever does not scan inside these lists.
|
|
35
|
-
|
|
36
|
-
| Block | Field Path | Description |
|
|
37
|
-
|---|---|---|
|
|
38
|
-
| `ContentLinks` | `items[*].source` | A list of hand-picked content items. |
|
|
39
|
-
| `RelevantAceContent` | `items[*].source` | A list of hand-picked content items (assigned items). |
|
|
40
|
-
| `ASTNavigation` | `items[*].href` | Individual navigation steps in the AST map. |
|
|
41
|
-
|
|
42
|
-
### 4. Special Cases
|
|
43
|
-
|
|
44
|
-
#### `FlourishEmbedBlock`
|
|
45
|
-
- **Field**: `embed_code` (Textarea)
|
|
46
|
-
- **Status**: Not covered.
|
|
47
|
-
- **Reason**: Contains raw HTML/JS snippets. Discovery would require parsing the HTML for URLs, which is not performed by the standard block retrievers.
|
|
48
|
-
|
|
49
|
-
#### `TabsBlock` (Spotlight Variation)
|
|
50
|
-
- **Status**: Covered (indirectly).
|
|
51
|
-
- **Reason**: This is a container block. The `NestedBlocksVisitor` handles the recursion into its child blocks, so any links within those children will be discovered normally.
|
|
52
|
-
|
|
53
|
-
#### `ReadMore`
|
|
54
|
-
- **Status**: No Links.
|
|
55
|
-
- **Reason**: This is a behavioral block that manipulates the DOM of its siblings on the frontend. It does not store links in its own block data.
|
|
56
|
-
|
|
57
|
-
## Recommendations for Link Integrity
|
|
58
|
-
|
|
59
|
-
To ensure full coverage for `volto-cca-policy` content, the following actions are recommended:
|
|
60
|
-
|
|
61
|
-
1. **Backend Adapters**: Register custom `IBlockFieldLinkIntegrityRetriever` adapters for `ContentLinks`, `RelevantAceContent`, and `ASTNavigation` to extract links from their `items` lists.
|
|
62
|
-
2. **Field Mapping**: If possible, refactor `ContentLinks` and `RelevantAceContent` to use `href` or `url` instead of `source` for individual items, although a custom retriever is still needed for the list structure.
|
|
63
|
-
3. **Core Coverage**: Verify if `plone.restapi` or `plone.volto` provides a specialized retriever for the `listing` block's `linkTo` field. If not, one should be added.
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# How Volto Discovers Links in Blocks for Link Integrity
|
|
2
|
-
|
|
3
|
-
When a content item is saved in Plone, the system needs to know which other internal items it links to, so it can maintain the `zc.relation` catalog (specifically using the `isReferencing` relationship).
|
|
4
|
-
|
|
5
|
-
For traditional Plone, this meant parsing HTML in `RichText` fields. For Volto, the content is stored as JSON blocks, requiring a recursive discovery mechanism.
|
|
6
|
-
|
|
7
|
-
## Sub-block Storage and Discovery
|
|
8
|
-
|
|
9
|
-
Sub-blocks are stored in the JSON data of a parent block using one of two primary patterns. The Plone backend uses a recursive generator called `visit_blocks` (defined in `plone.restapi.blocks`) to walk this tree.
|
|
10
|
-
|
|
11
|
-
### 1. Dictionary Mapping (Key-Value)
|
|
12
|
-
This is the standard Volto pattern for container-like blocks.
|
|
13
|
-
- **Storage Pattern**: A dictionary where keys are UUIDs and values are the sub-block data.
|
|
14
|
-
- **Common Keys**: `blocks` or `data["blocks"]`.
|
|
15
|
-
- **Discovery**: `plone.restapi.blocks.NestedBlocksVisitor` is registered for these keys. It yields each value in the dictionary.
|
|
16
|
-
|
|
17
|
-
### 2. Sequential Lists
|
|
18
|
-
This pattern is used by layout-oriented blocks where the order is strictly positional.
|
|
19
|
-
- **Storage Pattern**: A simple list of block data objects.
|
|
20
|
-
- **Core Volto Keys**: `columns`, `slides`, `hrefList`.
|
|
21
|
-
- **Discovery**: `plone.volto.transforms.NestedBlocksVisitor` handles these keys. It iterates through the list and yields each block.
|
|
22
|
-
|
|
23
|
-
### 3. Recursive Discovery Logic
|
|
24
|
-
The `visit_blocks` function uses `IBlockVisitor` subscribers to find children. When a visitor yields a sub-block, `visit_blocks` immediately recurses into that sub-block. This ensures that a block tree of any depth (e.g., a Grid containing Columns containing Teasers) is fully flattened during the discovery phase.
|
|
25
|
-
|
|
26
|
-
## Internal Link Extraction
|
|
27
|
-
|
|
28
|
-
Once a block is discovered, the `BlocksRetriever` (in `plone.restapi.blocks_linkintegrity`) uses `IBlockFieldLinkIntegrityRetriever` subscribers to find internal links within that specific block's fields.
|
|
29
|
-
|
|
30
|
-
### Automatic Link Detection (The Generic Retriever)
|
|
31
|
-
The `GenericBlockLinksRetriever` provides a "zero-configuration" discovery for most custom blocks. It automatically scans the following fields if they contain the `resolveuid/` pattern:
|
|
32
|
-
- `url`
|
|
33
|
-
- `href`
|
|
34
|
-
- `preview_image`
|
|
35
|
-
|
|
36
|
-
**Note**: If a block uses custom field names for links (e.g., `source`, `target`, `link_to`), they will **NOT** be caught by the generic retriever unless they are specifically registered.
|
|
37
|
-
|
|
38
|
-
### Complex Data Extraction
|
|
39
|
-
Some blocks store links deep within complex JSON structures rather than simple top-level strings. These require specialized retrievers:
|
|
40
|
-
|
|
41
|
-
1. **Slate Blocks (Rich Text)**:
|
|
42
|
-
- Uses `SlateBlockLinksRetriever`.
|
|
43
|
-
- Recursively walks the Slate node tree.
|
|
44
|
-
- Extracts UIDs from `data.link.internal.internal_link[0]["@id"]` and `data.url`.
|
|
45
|
-
|
|
46
|
-
2. **DraftJS Blocks (Legacy Text)**:
|
|
47
|
-
- Uses `TextBlockLinksRetriever`.
|
|
48
|
-
- Parses the `entityMap` for `LINK` entities.
|
|
49
|
-
- Extracts data from `url` and `href` keys within the entity data.
|
|
50
|
-
|
|
51
|
-
## Redundancy and Reliability
|
|
52
|
-
To ensure maximum reliability, `plone.volto` includes a `NestedBlockLinkRetriever` (registered with `block_type = None`). This serves as a fail-safe that manually walks the `columns`, `hrefList`, and `slides` keys to trigger link extraction, providing a second layer of defense for nested layouts.
|
|
53
|
-
|
|
54
|
-
## Summary for Developers
|
|
55
|
-
To ensure a custom block is correctly tracked by the link integrity system:
|
|
56
|
-
|
|
57
|
-
1. **Field Naming**: Prefer naming your link fields `url` or `href` to benefit from the generic retriever.
|
|
58
|
-
2. **Nesting**: If your block contains sub-blocks, store them in a dictionary under the key `blocks`.
|
|
59
|
-
3. **Link Format**: Always store internal links using the `resolveuid/<UID>` format.
|
|
60
|
-
4. **Custom Retrievers**: If you must use unique field names or storage patterns, register a custom `IBlockFieldLinkIntegrityRetriever` adapter for your block's `@type` in the backend.
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
# Test Fix Specification for volto-cca-policy
|
|
2
|
-
|
|
3
|
-
> Generated: 2026-05-14
|
|
4
|
-
> Branch: `link-integrity-workflow`
|
|
5
|
-
> Machine timezone: EEST (UTC+3)
|
|
6
|
-
|
|
7
|
-
## Current State
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
Test Suites: 4 failed, 57 passed, 61 total
|
|
11
|
-
Tests: 7 failed, 115 passed, 122 total
|
|
12
|
-
Snapshots: 6 failed, 12 passed, 18 total
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Four test suites fail for three distinct root causes:
|
|
16
|
-
|
|
17
|
-
| # | Test File | Failure Type | Root Cause |
|
|
18
|
-
|---|-----------|-------------|------------|
|
|
19
|
-
| 1 | `Spotlight.test.jsx` | Suite won't run | `node:crypto` module resolution (uuid@10 + Jest 26) |
|
|
20
|
-
| 2 | `GeolocationWidget.test.jsx` | Assertion error | Mock path mismatch → real OpenLayers loads in Jest |
|
|
21
|
-
| 3 | `EventView.test.jsx` | 3 snapshot mismatches | Timezone-dependent date formatting |
|
|
22
|
-
| 4 | `CcaEventView.test.jsx` | 3 snapshot mismatches | Timezone-dependent date formatting |
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Problem 1: `node:crypto` — Spotlight.test.jsx
|
|
27
|
-
|
|
28
|
-
### Symptom
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
ENOENT: no such file or directory, open 'node:crypto'
|
|
32
|
-
at Runtime.readFile (node_modules/jest-runtime/build/index.js:1987:21)
|
|
33
|
-
at Object.<anonymous> (node_modules/uuid/dist/rng.js:7:42)
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Root Cause
|
|
37
|
-
|
|
38
|
-
The `uuid` package (v10.0.0) uses `require('node:crypto')` — the Node.js built-in module protocol prefix (`node:`). Jest 26.6.3 does not understand this protocol and tries to resolve `node:crypto` as a filesystem path, which fails.
|
|
39
|
-
|
|
40
|
-
`Spotlight.test.jsx` doesn't import `uuid` directly. It's a transitive dependency pulled in through Volto core or one of its addons when the Spotlight component tree is evaluated.
|
|
41
|
-
|
|
42
|
-
### Proposed Fix
|
|
43
|
-
|
|
44
|
-
Add a `moduleNameMapper` entry in `jest-addon.config.js` to redirect `node:crypto` to the real Node.js `crypto` module:
|
|
45
|
-
|
|
46
|
-
**File: `jest-addon.config.js`**
|
|
47
|
-
|
|
48
|
-
In the `moduleNameMapper` section, add:
|
|
49
|
-
|
|
50
|
-
```js
|
|
51
|
-
'^node:crypto$': 'crypto',
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
This tells Jest to resolve `node:crypto` to the standard `crypto` module, which Node.js provides natively and Jest can handle.
|
|
55
|
-
|
|
56
|
-
**Why this approach:**
|
|
57
|
-
- Minimal: one line in the config, no new files needed.
|
|
58
|
-
- Follows the established pattern used across the addon ecosystem (moduleNameMapper entries in jest-addon.config.js).
|
|
59
|
-
- Does NOT require creating a mock file (the AI agent's `crypto-mock.js` approach).
|
|
60
|
-
- The real `crypto` module works fine in Jest's Node.js environment — it just needs the `node:` prefix stripped.
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Problem 2: Mock path mismatch — GeolocationWidget.test.jsx
|
|
65
|
-
|
|
66
|
-
### Symptom
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
Invalid lib or bundle name ol,olCondition,olControl,olCoordinate,olEvents,olExtent,olFormat,olGeom,olInteraction,olLayer,olLoadingstrategy,olOverlay,olProj,olRender,olSource,olStyle,olTilegrid
|
|
70
|
-
at flattenLazyBundle (Loadable/Loadable.js:30:11)
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Root Cause
|
|
74
|
-
|
|
75
|
-
Two layers of the problem:
|
|
76
|
-
|
|
77
|
-
**Layer 1 — Webpack vs Jest module resolution mismatch:**
|
|
78
|
-
|
|
79
|
-
Volto's webpack config uses `RelativeResolverPlugin` (`webpack-plugins/webpack-relative-resolver.js`) which rewrites relative imports into absolute addon-scoped paths at build time. For example, in production:
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
import MapContainer from './GeolocationWidgetMapContainer'
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
gets resolved by webpack to:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Jest does **not** use webpack. It resolves `./GeolocationWidgetMapContainer` as a relative filesystem path. So the two environments resolve the same import line to **different module identifiers**.
|
|
92
|
-
|
|
93
|
-
**Layer 2 — The test mocks the absolute path, but Jest loads the relative path:**
|
|
94
|
-
|
|
95
|
-
```js
|
|
96
|
-
// In the test — mocks the absolute (webpack-resolved) path:
|
|
97
|
-
jest.mock(
|
|
98
|
-
'@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer',
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
// But GeolocationWidget.jsx imports it relatively:
|
|
102
|
-
import MapContainer from './GeolocationWidgetMapContainer';
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
In Jest, these are two different modules. The mock never applies. The real `GeolocationWidgetMapContainer` loads, which uses the `withOpenLayers` HOC from `volto-openlayers-map`. That HOC calls `useLazyLibs()` to dynamically load OpenLayers bundles, which crashes in Jest's environment.
|
|
106
|
-
|
|
107
|
-
### Proposed Fix
|
|
108
|
-
|
|
109
|
-
Two options. **Option A is recommended** because it fixes the source code to match the project convention (the rest of the codebase uses `@eeacms/volto-cca-policy/...` absolute imports — the relative import in `GeolocationWidget.jsx` is the outlier).
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
#### Option A: Change the source code to use the absolute import (recommended)
|
|
114
|
-
|
|
115
|
-
**File: `src/components/theme/Widgets/GeolocationWidget.jsx`**
|
|
116
|
-
|
|
117
|
-
Replace:
|
|
118
|
-
|
|
119
|
-
```js
|
|
120
|
-
import MapContainer from './GeolocationWidgetMapContainer';
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
With:
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
import MapContainer from '@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer';
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
This makes the import consistent with the rest of the codebase (20+ files in this addon use `@eeacms/volto-cca-policy/...` imports). The existing test mock path (`@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer`) will now match in **both** webpack and Jest environments. No test file changes needed.
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
#### Option B: Mock both paths in the test file
|
|
134
|
-
|
|
135
|
-
If changing the source code is not desired, mock **both** the relative and absolute paths in the test:
|
|
136
|
-
|
|
137
|
-
**File: `src/components/theme/Widgets/GeolocationWidget.test.jsx`**
|
|
138
|
-
|
|
139
|
-
Replace:
|
|
140
|
-
|
|
141
|
-
```js
|
|
142
|
-
jest.mock(
|
|
143
|
-
'@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer',
|
|
144
|
-
);
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
With:
|
|
148
|
-
|
|
149
|
-
```js
|
|
150
|
-
const MapContainerMock = () => <div id="map-container-mock" />;
|
|
151
|
-
|
|
152
|
-
// Mock the relative path (what Jest resolves):
|
|
153
|
-
jest.mock('./GeolocationWidgetMapContainer', () => MapContainerMock);
|
|
154
|
-
|
|
155
|
-
// Mock the absolute path (what webpack resolves — belt and suspenders):
|
|
156
|
-
jest.mock(
|
|
157
|
-
'@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer',
|
|
158
|
-
() => MapContainerMock,
|
|
159
|
-
);
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
**Why Option A is preferred:**
|
|
163
|
-
- One-line source code change, zero test changes.
|
|
164
|
-
- The relative import `./GeolocationWidgetMapContainer` is the **only** relative import to a sibling file within this addon's component tree. Every other internal import in `volto-cca-policy` uses the `@eeacms/volto-cca-policy/...` convention.
|
|
165
|
-
- Fixes the root cause (import inconsistency) rather than working around it in every test file.
|
|
166
|
-
- The existing test mock already targets the correct absolute path — it just never matched because of the relative import in the source.
|
|
167
|
-
|
|
168
|
-
---
|
|
169
|
-
|
|
170
|
-
## Problem 3 & 4: Timezone-dependent snapshots — EventView.test.jsx, CcaEventView.test.jsx
|
|
171
|
-
|
|
172
|
-
### Symptom
|
|
173
|
-
|
|
174
|
-
```
|
|
175
|
-
- Snapshot - 2
|
|
176
|
-
+ Received + 2
|
|
177
|
-
|
|
178
|
-
<span className="start-time">
|
|
179
|
-
- 3:20 PM
|
|
180
|
-
+ 6:20 PM
|
|
181
|
-
</span>
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
The snapshots expect `3:20 PM` but the test produces `6:20 PM` (a 3-hour offset = UTC vs EEST).
|
|
185
|
-
|
|
186
|
-
### Root Cause
|
|
187
|
-
|
|
188
|
-
The test data uses UTC timestamps (e.g., `'2019-06-23T15:20:00+00:00'`). The `EventDetails` component (from `@eeacms/volto-cca-policy/helpers`) formats these dates using JavaScript's built-in `Date` methods, which convert to the **local timezone**. The snapshots were recorded on a machine in UTC (or a timezone with offset 0), but the current test machine is in EEST (UTC+3).
|
|
189
|
-
|
|
190
|
-
The snapshots contain:
|
|
191
|
-
- `3:20 PM` for `15:20:00+00:00` — correct in UTC
|
|
192
|
-
- `4:20 PM` for `16:20:00+00:00` — correct in UTC
|
|
193
|
-
|
|
194
|
-
On EEST, these render as `6:20 PM` and `7:20 PM` respectively.
|
|
195
|
-
|
|
196
|
-
### Proposed Fix
|
|
197
|
-
|
|
198
|
-
Set `TZ=UTC` for the Jest process so date formatting is deterministic and matches the snapshots. This is done via the `TZ` environment variable, which is the standard, cross-platform way to control timezone in JavaScript tests.
|
|
199
|
-
|
|
200
|
-
Two approaches (pick one):
|
|
201
|
-
|
|
202
|
-
**Approach A — Makefile target (recommended):**
|
|
203
|
-
|
|
204
|
-
Modify the `test` target in `frontend/Makefile` to set `TZ=UTC`:
|
|
205
|
-
|
|
206
|
-
```makefile
|
|
207
|
-
test: ## Run Jest tests for Volto add-on
|
|
208
|
-
TZ=UTC RAZZLE_JEST_CONFIG=$(filter-out $@,$(MAKECMDGOALS))/jest-addon.config.js yarn test $(filter-out $@,$(MAKECMDGOALS))
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
This is the cleanest approach because:
|
|
212
|
-
- It applies to ALL addon tests consistently, preventing the same issue in other addons.
|
|
213
|
-
- No changes needed in individual test files.
|
|
214
|
-
- `TZ=UTC` is the standard approach for timezone-independent tests in CI environments.
|
|
215
|
-
|
|
216
|
-
**Approach B — jest.setup.js (if Approach A is not preferred):**
|
|
217
|
-
|
|
218
|
-
Add to `jest.setup.js` (at the top, before any imports that might use Date):
|
|
219
|
-
|
|
220
|
-
```js
|
|
221
|
-
// Ensure deterministic timezone for snapshot tests
|
|
222
|
-
process.env.TZ = 'UTC';
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
**Why this approach:**
|
|
226
|
-
- `TZ=UTC` is the established convention for deterministic date formatting in tests.
|
|
227
|
-
- Does not modify the component code or test data.
|
|
228
|
-
- Does not require updating snapshots — the tests will produce the same output as the recorded snapshots.
|
|
229
|
-
- Solves the problem for any future tests that render dates.
|
|
230
|
-
|
|
231
|
-
---
|
|
232
|
-
|
|
233
|
-
## Summary of Changes
|
|
234
|
-
|
|
235
|
-
### Option A (recommended — fix source import)
|
|
236
|
-
|
|
237
|
-
| File | Change | Lines |
|
|
238
|
-
|------|--------|-------|
|
|
239
|
-
| `jest-addon.config.js` | Add `'^node:crypto$': 'crypto'` to `moduleNameMapper` | +1 |
|
|
240
|
-
| `src/components/theme/Widgets/GeolocationWidget.jsx` | Change `import ... from './GeolocationWidgetMapContainer'` → `import ... from '@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer'` | 1 line |
|
|
241
|
-
| `frontend/Makefile` (root) | Add `TZ=UTC` to the `test` target | +1 |
|
|
242
|
-
|
|
243
|
-
### Option B (mock both paths in test)
|
|
244
|
-
|
|
245
|
-
| File | Change | Lines |
|
|
246
|
-
|------|--------|-------|
|
|
247
|
-
| `jest-addon.config.js` | Add `'^node:crypto$': 'crypto'` to `moduleNameMapper` | +1 |
|
|
248
|
-
| `src/components/theme/Widgets/GeolocationWidget.test.jsx` | Mock both `./GeolocationWidgetMapContainer` and `@eeacms/.../GeolocationWidgetMapContainer` | ~6 lines |
|
|
249
|
-
| `frontend/Makefile` (root) | Add `TZ=UTC` to the `test` target | +1 |
|
|
250
|
-
|
|
251
|
-
**No changes needed to:**
|
|
252
|
-
- `jest.setup.js` — the existing setup (with `thunk` middleware) is correct.
|
|
253
|
-
- `EventView.test.jsx` or `CcaEventView.test.jsx` — the snapshots are correct (UTC), the timezone environment is the fix.
|
|
254
|
-
- Any snapshot files — once `TZ=UTC` is set, they will match.
|
|
255
|
-
- `GeolocationWidget.test.jsx` (Option A only) — the existing absolute-path mock already works once the source import is aligned.
|
|
256
|
-
|
|
257
|
-
## What the Previous AI Agent Did Wrong
|
|
258
|
-
|
|
259
|
-
The previous attempt made these changes (now stashed/discarded):
|
|
260
|
-
|
|
261
|
-
1. **`jest.setup.js` — massive rewrite:** Mocked `uuid`, `redux-mock-store`, `useLazyLibs` globally; added `lazyBundles`/`loadables` config; switched to CommonJS `require()`. This was overly invasive — it changed the global test environment for ALL 61 test suites, introducing risk of masking real issues.
|
|
262
|
-
|
|
263
|
-
2. **`EventView.test.jsx` and `CcaEventView.test.jsx`:** Removed the `jest.mock('Loadable')` + `beforeAll(__setLoadables())` pattern. This was counterproductive — the Loadable mock is the established pattern used by 19+ test files across the addons. Removing it doesn't fix the timezone issue at all.
|
|
264
|
-
|
|
265
|
-
3. **`GeolocationWidget.test.jsx`:** Added `thunk` middleware to the local `configureStore()` call. Unnecessary — `jest.setup.js` already configures `configureStore([thunk])` globally. Also changed the mock path to `./GeolocationWidgetMapContainer` which fixes the Jest-side resolution but doesn't address the root cause: the source code uses a relative import where the rest of the codebase uses absolute `@eeacms/...` imports, creating a webpack/Jest resolution mismatch.
|
|
266
|
-
|
|
267
|
-
4. **Created `src/crypto-mock.js`:** An unnecessary file when `moduleNameMapper: 'node:crypto' -> 'crypto'` solves it in one line.
|