Skip to content

Commit 65e2d0a

Browse files
authored
refactor(sdk-analytics): Consolidate analytics data attributes and simplify Contentlet component (#33948)
## Summary Consolidates analytics data attributes by moving constants from UVE to sdk-analytics and simplifies the sdk-react `Contentlet` component by removing redundant analytics state management. Analytics attributes now always render using UVE's standard contentlet attributes instead of separate conditional logic. ## Changes Made ### SDK Analytics (`libs/sdk/analytics`) - **Moved analytics constants** from `@dotcms/uve/internal` to `sdk-analytics/constants`: - `ANALYTICS_WINDOWS_ACTIVE_KEY` - Analytics active state flag - `ANALYTICS_WINDOWS_CLEANUP_KEY` - Analytics cleanup function reference - `CONTENTLET_CLASS` - Renamed from `ANALYTICS_CONTENTLET_CLASS` to `dotcms-contentlet` - **Updated data attribute naming** to use standard UVE attributes: - `data-dot-analytics-identifier` → `data-dot-identifier` - `data-dot-analytics-inode` → `data-dot-inode` - `data-dot-analytics-contenttype` → `data-dot-type` - `data-dot-analytics-title` → `data-dot-title` - `data-dot-analytics-basetype` → `data-dot-basetype` - `data-dot-analytics-dom-index` → `data-dot-dom-index` - **Updated all analytics plugins** to use consolidated constants and new attribute names: - [dot-analytics.content.ts](core-web/libs/sdk/analytics/src/lib/core/dot-analytics.content.ts) - [dot-analytics.identity.activity-tracker.ts](core-web/libs/sdk/analytics/src/lib/core/plugin/identity/dot-analytics.identity.activity-tracker.ts) - [dot-analytics.impression-tracker.ts](core-web/libs/sdk/analytics/src/lib/core/plugin/impression/dot-analytics.impression-tracker.ts) - [dot-analytics.utils.ts](core-web/libs/sdk/analytics/src/lib/core/shared/utils/dot-analytics.utils.ts) ### SDK React (`libs/sdk/react`) - **Removed `useIsAnalyticsActive` hook** ([useIsAnalyticsActive.ts](core-web/libs/sdk/react/src/lib/next/hooks/useIsAnalyticsActive.ts)) - No longer needed since analytics attributes always render via UVE - **Simplified `Contentlet` component** ([Contentlet.tsx:55-78](core-web/libs/sdk/react/src/lib/next/components/Contentlet/Contentlet.tsx#L55-L78)): - Removed conditional `analyticsAttributes` useMemo - Removed conditional `containerClassName` useMemo - Removed `isAnalyticsActive` state check - Always applies UVE attributes via `getDotContentletAttributes()` - Always applies `CONTENTLET_CLASS` (`dotcms-contentlet`) - **Updated tests** ([Contentlet.test.tsx](core-web/libs/sdk/react/src/lib/next/__test__/components/Contentlet.test.tsx)): - Removed `useIsAnalyticsActive` mock - Removed `getDotAnalyticsAttributes` mock - Updated assertions to reflect always-rendered attributes - Simplified test cases (removed analytics conditional tests) ### SDK UVE (`libs/sdk/uve`) - **Removed analytics-specific exports** from UVE internal API: - Removed `getDotAnalyticsAttributes()` function (analytics now uses standard UVE attributes) - Removed `isAnalyticsActive()` function (no longer needed) - Removed `ANALYTICS_WINDOWS_ACTIVE_KEY` and `ANALYTICS_WINDOWS_CLEANUP_KEY` constants (moved to sdk-analytics) - Removed 50+ lines of analytics-specific tests ## Technical Details **Problem**: The sdk-react `Contentlet` component had duplicate analytics attribute logic that conditionally rendered based on `isAnalyticsActive && !isDevMode`. This created complexity and separated analytics attributes from UVE's standard contentlet attributes. **Solution**: 1. Consolidate analytics constants in `@dotcms/analytics` where they belong 2. Use UVE's standard `getDotContentletAttributes()` which already provides all necessary data attributes 3. Remove conditional rendering - analytics attributes always render via the standard `data-dot-*` attributes 4. Standardize CSS class to `dotcms-contentlet` (used by both UVE and analytics) **Benefits**: - **Simpler component logic** - No analytics state management needed - **Consistent data attributes** - Single source of truth (UVE) - **Better separation of concerns** - Analytics constants live in analytics SDK - **Always-on tracking** - Analytics attributes always present (no missed tracking events) ## Breaking Changes **CSS Class Change**: The analytics contentlet class changed from `dotcms-analytics-contentlet` to `dotcms-contentlet`. This aligns with UVE's standard class and should not affect existing implementations as both classes serve the same selector purpose. **Data Attribute Changes**: Analytics data attributes now use standard UVE naming (`data-dot-*` instead of `data-dot-analytics-*`). The analytics SDK internally handles reading these attributes, so no client-side changes are needed. ## Testing - [x] Unit tests updated for `Contentlet` component - [x] Unit tests updated for analytics plugins (impression tracker, identity tracker) - [x] Removed obsolete analytics state tests - [x] All tests passing ## Related Issues Closes #33947 ## Additional Notes This refactoring aligns with the strategy to consolidate analytics functionality and reduce code duplication across the SDK. Future enhancements can build on this simplified foundation without managing separate analytics attribute logic. The change ensures analytics tracking is always active and consistent, removing edge cases where analytics might be disabled outside Edit Mode.
1 parent 98de141 commit 65e2d0a

File tree

16 files changed

+97
-329
lines changed

16 files changed

+97
-329
lines changed

core-web/libs/sdk/analytics/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ The `impressions` option controls automatic tracking of content visibility:
247247

248248
**How it works:**
249249

250-
- ✅ Tracks contentlets marked with `dotcms-analytics-contentlet` class and `data-dot-analytics-*` attributes
250+
- ✅ Tracks contentlets marked with `dotcms-contentlet` class and `data-dot-*` attributes (e.g., `data-dot-identifier`, `data-dot-inode`, `data-dot-type`)
251251
- ✅ Uses Intersection Observer API for high performance and battery efficiency
252252
- ✅ Only fires when element is ≥50% visible for ≥750ms (configurable)
253253
- ✅ Only tracks during active tab (respects page visibility)
@@ -299,7 +299,7 @@ The `clicks` option controls automatic tracking of user interactions with conten
299299
**How it works:**
300300

301301
- ✅ Tracks clicks on `<a>` and `<button>` elements within contentlets
302-
- ✅ Contentlets must be marked with `dotcms-analytics-contentlet` class and `data-dot-analytics-*` attributes
302+
- ✅ Contentlets must be marked with `dotcms-contentlet` class and `data-dot-*` attributes (e.g., `data-dot-identifier`, `data-dot-inode`, `data-dot-type`)
303303
- ✅ Captures semantic attributes (`href`, `aria-label`, `data-*`) and excludes CSS classes
304304
- ✅ Throttles rapid clicks to prevent duplicate tracking (300ms fixed)
305305
- ✅ One click event per interaction
@@ -341,7 +341,7 @@ The `attributes` array captures additional semantic data in `'key:value'` string
341341
- `class` - Already captured as top-level property
342342
- `id` - Already captured as top-level property
343343
- `href` - Already captured as top-level property
344-
- `data-dot-analytics-*` - Internal SDK attributes
344+
- `data-dot-*` - Internal SDK attributes (e.g., `data-dot-identifier`, `data-dot-inode`, `data-dot-type`)
345345

346346
**Example: Enable click tracking**
347347

core-web/libs/sdk/analytics/src/lib/core/dot-analytics.content.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Analytics } from 'analytics';
22

3-
import { ANALYTICS_WINDOWS_ACTIVE_KEY, ANALYTICS_WINDOWS_CLEANUP_KEY } from '@dotcms/uve/internal';
4-
53
import { dotAnalyticsClickPlugin } from './plugin/click/dot-analytics.click.plugin';
64
import { dotAnalyticsEnricherPlugin } from './plugin/enricher/dot-analytics.enricher.plugin';
75
import { dotAnalyticsIdentityPlugin } from './plugin/identity/dot-analytics.identity.plugin';
86
import { dotAnalyticsImpressionPlugin } from './plugin/impression/dot-analytics.impression.plugin';
97
import { dotAnalytics } from './plugin/main/dot-analytics.plugin';
10-
import { DotCMSPredefinedEventType } from './shared/constants/dot-analytics.constants';
8+
import {
9+
ANALYTICS_WINDOWS_ACTIVE_KEY,
10+
ANALYTICS_WINDOWS_CLEANUP_KEY,
11+
DotCMSPredefinedEventType
12+
} from './shared/constants/dot-analytics.constants';
1113
import {
1214
DotCMSAnalytics,
1315
DotCMSAnalyticsConfig,

core-web/libs/sdk/analytics/src/lib/core/plugin/identity/dot-analytics.identity.activity-tracker.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22

3-
import { ANALYTICS_WINDOWS_ACTIVE_KEY, ANALYTICS_WINDOWS_CLEANUP_KEY } from '@dotcms/uve/internal';
4-
53
import {
64
cleanupActivityTracking,
75
initializeActivityTracking,
86
updateSessionActivity
97
} from './dot-analytics.identity.activity-tracker';
108

119
import { ACTIVITY_EVENTS } from '../../shared/constants';
10+
import {
11+
ANALYTICS_WINDOWS_ACTIVE_KEY,
12+
ANALYTICS_WINDOWS_CLEANUP_KEY
13+
} from '../../shared/constants/dot-analytics.constants';
1214
import { DotCMSAnalyticsConfig } from '../../shared/models';
1315

1416
describe('DotCMS Activity Tracker', () => {

core-web/libs/sdk/analytics/src/lib/core/plugin/identity/dot-analytics.identity.activity-tracker.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { ANALYTICS_WINDOWS_ACTIVE_KEY, ANALYTICS_WINDOWS_CLEANUP_KEY } from '@dotcms/uve/internal';
2-
3-
import { ACTIVITY_EVENTS, DEFAULT_SESSION_TIMEOUT_MINUTES } from '../../shared/constants';
1+
import {
2+
ACTIVITY_EVENTS,
3+
ANALYTICS_WINDOWS_ACTIVE_KEY,
4+
ANALYTICS_WINDOWS_CLEANUP_KEY,
5+
DEFAULT_SESSION_TIMEOUT_MINUTES
6+
} from '../../shared/constants';
47
import { DotCMSAnalyticsConfig } from '../../shared/models';
58

69
// Extend window interface for cleanup function

core-web/libs/sdk/analytics/src/lib/core/plugin/impression/dot-analytics.impression-tracker.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getUVEState } from '@dotcms/uve';
55
import { DotCMSImpressionTracker } from './dot-analytics.impression-tracker';
66

77
import {
8-
ANALYTICS_CONTENTLET_CLASS,
8+
CONTENTLET_CLASS,
99
DEFAULT_IMPRESSION_CONFIG,
1010
IMPRESSION_EVENT_TYPE
1111
} from '../../shared/constants/dot-analytics.constants';
@@ -41,12 +41,12 @@ describe('DotCMSImpressionTracker', () => {
4141
} = {}
4242
): HTMLElement => {
4343
const element = document.createElement('div');
44-
element.className = ANALYTICS_CONTENTLET_CLASS;
45-
element.dataset.dotAnalyticsIdentifier = identifier;
46-
element.dataset.dotAnalyticsInode = options.inode || 'inode-123';
47-
element.dataset.dotAnalyticsContenttype = options.contentType || 'Blog';
48-
element.dataset.dotAnalyticsTitle = options.title || 'Test Content';
49-
element.dataset.dotAnalyticsBasetype = options.baseType || 'CONTENT';
44+
element.className = CONTENTLET_CLASS;
45+
element.dataset.dotIdentifier = identifier;
46+
element.dataset.dotInode = options.inode || 'inode-123';
47+
element.dataset.dotType = options.contentType || 'Blog';
48+
element.dataset.dotTitle = options.title || 'Test Content';
49+
element.dataset.dotBasetype = options.baseType || 'CONTENT';
5050

5151
// Mock getBoundingClientRect
5252
element.getBoundingClientRect = jest.fn(() => ({
@@ -304,8 +304,8 @@ describe('DotCMSImpressionTracker', () => {
304304

305305
it('should skip elements without identifier', () => {
306306
const element = document.createElement('div');
307-
element.className = ANALYTICS_CONTENTLET_CLASS;
308-
// No data-dot-analytics-identifier
307+
element.className = CONTENTLET_CLASS;
308+
// No data-dot-identifier
309309
document.body.appendChild(element);
310310

311311
tracker = new DotCMSImpressionTracker(mockConfig);

core-web/libs/sdk/analytics/src/lib/core/plugin/impression/dot-analytics.impression-tracker.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ export class DotCMSImpressionTracker {
182182

183183
// Only observe and initialize if this is a new element
184184
if (!this.elementImpressionStates.has(identifier)) {
185-
if (!element.dataset.dotAnalyticsDomIndex) {
186-
element.dataset.dotAnalyticsDomIndex = String(i);
185+
if (!element.dataset.dotDomIndex) {
186+
element.dataset.dotDomIndex = String(i);
187187
}
188188

189189
this.observer.observe(element);
@@ -386,7 +386,7 @@ export class DotCMSImpressionTracker {
386386

387387
// Read cached DOM index instead of expensive query
388388
// Falls back to -1 if not cached (should never happen in normal flow)
389-
const domIndex = parseInt(element.dataset.dotAnalyticsDomIndex || '-1', 10);
389+
const domIndex = parseInt(element.dataset.dotDomIndex || '-1', 10);
390390

391391
// Build impression payload (enricher plugin adds page data automatically)
392392
const impressionPayload: DotCMSContentImpressionPayload = {

core-web/libs/sdk/analytics/src/lib/core/shared/constants/dot-analytics.constants.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,34 @@ export const CLICKABLE_ELEMENTS_SELECTOR = 'a, button';
185185
export const IMPRESSION_SESSION_KEY = 'dot_analytics_impressions';
186186

187187
/**
188-
* CSS class selector for trackable contentlets
188+
* Window property key for analytics active state
189+
* Used to track if analytics is initialized and active
189190
*/
190-
export const ANALYTICS_CONTENTLET_CLASS = 'dotcms-analytics-contentlet';
191+
export const ANALYTICS_WINDOWS_ACTIVE_KEY = '__dotAnalyticsActive__';
192+
193+
/**
194+
* Window property key for analytics cleanup function
195+
* Used to store the cleanup function for analytics instance
196+
*/
197+
export const ANALYTICS_WINDOWS_CLEANUP_KEY = '__dotAnalyticsCleanup__';
198+
199+
/**
200+
* CSS class selector for contentlet elements
201+
*
202+
* @important This constant is intentionally duplicated in @dotcms/react SDK
203+
* (core-web/libs/sdk/react/src/lib/next/components/Contentlet/Contentlet.tsx).
204+
* Both constants MUST have the same value ('dotcms-contentlet') for analytics
205+
* tracking to work correctly with React-rendered contentlets.
206+
*
207+
* This duplication is intentional to maintain SDK independence:
208+
* - @dotcms/analytics can be used standalone without React
209+
* - @dotcms/react can be used without analytics
210+
* - When both are used together, they must share the same class name
211+
*
212+
* If you need to change this value, you MUST update it in both locations:
213+
* 1. This file (analytics SDK)
214+
* 2. Contentlet.tsx in React SDK
215+
*
216+
* @see core-web/libs/sdk/react/src/lib/next/components/Contentlet/Contentlet.tsx
217+
*/
218+
export const CONTENTLET_CLASS = 'dotcms-contentlet';

core-web/libs/sdk/analytics/src/lib/core/shared/utils/dot-analytics.utils.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { AnalyticsPlugin, PageData } from 'analytics';
22

33
import {
4-
ANALYTICS_CONTENTLET_CLASS,
54
ANALYTICS_JS_DEFAULT_PROPERTIES,
65
ANALYTICS_MINIFIED_SCRIPT_NAME,
6+
CONTENTLET_CLASS,
77
DEFAULT_IMPRESSION_MUTATION_OBSERVER_DEBOUNCE_MS,
88
DEFAULT_SESSION_TIMEOUT_MINUTES,
99
DotCMSPredefinedEventType,
@@ -635,7 +635,7 @@ export function createThrottle<T extends (...args: unknown[]) => void>(
635635
* @returns The contentlet identifier or null if not found
636636
*/
637637
export function extractContentletIdentifier(element: HTMLElement): string | null {
638-
return element.dataset.dotAnalyticsIdentifier || null;
638+
return element.dataset.dotIdentifier || null;
639639
}
640640

641641
/**
@@ -645,11 +645,11 @@ export function extractContentletIdentifier(element: HTMLElement): string | null
645645
*/
646646
export function extractContentletData(element: HTMLElement): ContentletData {
647647
return {
648-
identifier: element.dataset.dotAnalyticsIdentifier || '',
649-
inode: element.dataset.dotAnalyticsInode || '',
650-
contentType: element.dataset.dotAnalyticsContenttype || '',
651-
title: element.dataset.dotAnalyticsTitle || '',
652-
baseType: element.dataset.dotAnalyticsBasetype || ''
648+
identifier: element.dataset.dotIdentifier || '',
649+
inode: element.dataset.dotInode || '',
650+
contentType: element.dataset.dotType || '',
651+
title: element.dataset.dotTitle || '',
652+
baseType: element.dataset.dotBasetype || ''
653653
};
654654
}
655655

@@ -672,7 +672,7 @@ export const isBrowser = (): boolean => {
672672
* @returns Array of contentlet HTMLElements
673673
*/
674674
export const findContentlets = (): HTMLElement[] => {
675-
return Array.from(document.querySelectorAll<HTMLElement>(`.${ANALYTICS_CONTENTLET_CLASS}`));
675+
return Array.from(document.querySelectorAll<HTMLElement>(`.${CONTENTLET_CLASS}`));
676676
};
677677

678678
/**
@@ -710,12 +710,12 @@ export const createContentletObserver = (
710710
const element = node as HTMLElement;
711711

712712
// Check if node itself is a contentlet
713-
if (element.classList?.contains(ANALYTICS_CONTENTLET_CLASS)) {
713+
if (element.classList?.contains(CONTENTLET_CLASS)) {
714714
return true;
715715
}
716716

717717
// Check if node contains contentlets
718-
return element.querySelector?.(`.${ANALYTICS_CONTENTLET_CLASS}`) !== null;
718+
return element.querySelector?.(`.${CONTENTLET_CLASS}`) !== null;
719719
});
720720
});
721721

core-web/libs/sdk/react/src/lib/next/__test__/components/Contentlet.test.tsx

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import '@testing-library/jest-dom';
22

33
import { render, screen } from '@testing-library/react';
44

5-
import { getDotAnalyticsAttributes, getDotContentletAttributes } from '@dotcms/uve/internal';
5+
import { getDotContentletAttributes } from '@dotcms/uve/internal';
66

7-
import { Contentlet } from '../../components/Contentlet/Contentlet';
7+
import { Contentlet, CONTENTLET_CLASS } from '../../components/Contentlet/Contentlet';
88
import { DotCMSPageContext } from '../../contexts/DotCMSPageContext';
99
import { useCheckVisibleContent } from '../../hooks/useCheckVisibleContent';
10-
import { useIsAnalyticsActive } from '../../hooks/useIsAnalyticsActive';
1110

1211
jest.mock('../../components/FallbackComponent/FallbackComponent', () => ({
1312
FallbackComponent: ({ contentlet }: any) => (
@@ -20,13 +19,9 @@ jest.mock('../../hooks/useCheckVisibleContent', () => ({
2019
useCheckVisibleContent: jest.fn(() => false)
2120
}));
2221

23-
jest.mock('../../hooks/useIsAnalyticsActive', () => ({
24-
useIsAnalyticsActive: jest.fn(() => false)
25-
}));
26-
2722
jest.mock('@dotcms/uve/internal', () => ({
2823
getDotContentletAttributes: jest.fn(() => ({ 'data-custom': 'true' })),
29-
getDotAnalyticsAttributes: jest.fn(() => ({ 'data-analytics-custom': 'true' })),
24+
CUSTOM_NO_COMPONENT: 'CustomNoComponent',
3025
DEVELOPMENT_MODE: 'development',
3126
PRODUCTION_MODE: 'production'
3227
}));
@@ -42,15 +37,11 @@ describe('Contentlet', () => {
4237
};
4338

4439
const useCheckVisibleContentMock = useCheckVisibleContent as jest.Mock;
45-
const useIsAnalyticsActiveMock = useIsAnalyticsActive as jest.Mock;
4640
const getDotContentletAttributesMock = getDotContentletAttributes as jest.Mock;
47-
const getDotAnalyticsAttributesMock = getDotAnalyticsAttributes as jest.Mock;
4841

4942
beforeEach(() => {
5043
useCheckVisibleContentMock.mockReturnValue(false);
51-
useIsAnalyticsActiveMock.mockReturnValue(false);
5244
getDotContentletAttributesMock.mockClear();
53-
getDotAnalyticsAttributesMock.mockClear();
5445
});
5546

5647
test('should render fallback component when no custom component exists', () => {
@@ -64,6 +55,7 @@ describe('Contentlet', () => {
6455

6556
const containerDiv = screen.getByTestId('fallback').parentElement;
6657
expect(containerDiv).toHaveAttribute('data-dot-object', 'contentlet');
58+
expect(containerDiv).toHaveClass(CONTENTLET_CLASS);
6759

6860
expect(containerDiv).toHaveStyle('min-height: 4rem');
6961
expect(getDotContentletAttributesMock).toHaveBeenCalledWith(dummyContentlet, 'container-1');
@@ -98,12 +90,13 @@ describe('Contentlet', () => {
9890
container: 'container-1'
9991
});
10092

101-
expect(getDotContentletAttributes).not.toHaveBeenCalled();
93+
// UVE attributes should always be called
94+
expect(getDotContentletAttributesMock).toHaveBeenCalledWith(dummyContentlet, 'container-1');
10295

10396
const containerDiv = container.querySelector(
10497
'[data-dot-object="contentlet"]'
10598
) as HTMLElement;
106-
expect(containerDiv.className).toBe('');
99+
expect(containerDiv.className).toBe(CONTENTLET_CLASS);
107100
});
108101

109102
test('should not apply minHeight style if useCheckVisibleContent returns true', () => {
@@ -120,49 +113,39 @@ describe('Contentlet', () => {
120113
expect(containerDiv).not.toHaveStyle('min-height: 4rem');
121114
});
122115

123-
test('should add analytics attributes when isAnalyticsActive is true in production', () => {
124-
useIsAnalyticsActiveMock.mockReturnValue(true);
125-
116+
test('should always apply UVE attributes in production', () => {
126117
const contextValue = {
127118
mode: 'production',
128119
userComponents: {}
129120
};
130121

131122
renderContentlet(contextValue, { contentlet: dummyContentlet, container: 'container-1' });
132123

133-
// UVE attributes should NOT be called in production
134-
expect(getDotContentletAttributesMock).not.toHaveBeenCalled();
135-
// Analytics attributes SHOULD be called when analytics is active
136-
expect(getDotAnalyticsAttributesMock).toHaveBeenCalledWith(dummyContentlet);
124+
// UVE attributes should always be called
125+
expect(getDotContentletAttributesMock).toHaveBeenCalledWith(dummyContentlet, 'container-1');
137126
});
138127

139-
test('should not add any data attributes when both isDevMode and isAnalyticsActive are false', () => {
140-
useIsAnalyticsActiveMock.mockReturnValue(false);
141-
128+
test('should always apply UVE attributes even when isDevMode is false', () => {
142129
const contextValue = {
143130
mode: 'production',
144131
userComponents: {}
145132
};
146133

147134
renderContentlet(contextValue, { contentlet: dummyContentlet, container: 'container-1' });
148135

149-
expect(getDotContentletAttributesMock).not.toHaveBeenCalled();
150-
expect(getDotAnalyticsAttributesMock).not.toHaveBeenCalled();
136+
// UVE attributes should always be called
137+
expect(getDotContentletAttributesMock).toHaveBeenCalledWith(dummyContentlet, 'container-1');
151138
});
152139

153-
test('should NOT add analytics attributes when in development mode (UVE)', () => {
154-
useIsAnalyticsActiveMock.mockReturnValue(true);
155-
140+
test('should always apply UVE attributes in development mode (UVE)', () => {
156141
const contextValue = {
157142
mode: 'development',
158143
userComponents: {}
159144
};
160145

161146
renderContentlet(contextValue, { contentlet: dummyContentlet, container: 'container-1' });
162147

163-
// UVE attributes should be called in development
148+
// UVE attributes should always be called
164149
expect(getDotContentletAttributesMock).toHaveBeenCalledWith(dummyContentlet, 'container-1');
165-
// Analytics attributes should NOT be called in development mode (even if analytics is active)
166-
expect(getDotAnalyticsAttributesMock).not.toHaveBeenCalled();
167150
});
168151
});

0 commit comments

Comments
 (0)