Skip to content

Commit bdc6a1d

Browse files
authored
Merge pull request #183 from episerver/bugfix/CMS-47490-fix-src-handle-dam
CMS-47490 Refactor getPreviewUtils to improve URL handling
2 parents 42fd6fb + b2a5db4 commit bdc6a1d

File tree

4 files changed

+160
-12
lines changed

4 files changed

+160
-12
lines changed

packages/optimizely-cms-sdk/src/react/__test__/assetsUtils.test.tsx

Lines changed: 151 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,16 @@ describe('getPreviewUtils', () => {
6565
};
6666

6767
describe('src()', () => {
68-
it('should return empty string when not in preview mode', () => {
68+
it('should return item.Url when not in preview mode', () => {
6969
const utils = getPreviewUtils({ __typename: 'TestPage' });
7070
const result = utils.src(mockImageAsset);
7171

72-
expect(result).toBe('');
72+
expect(result).toBe(
73+
'https://assets.local-cms.com/0a2f4b27-4f15-4bb9-ba14-d69b49ae5b85/cmp_73d48db0-2abe-4a33-91f5-94d0ac5e85e5.jpg'
74+
);
7375
});
7476

75-
it('should append preview token to item URL', () => {
77+
it('should append preview token to item.Url in preview mode', () => {
7678
const utils = getPreviewUtils({
7779
__typename: 'TestPage',
7880
__context: { edit: true, preview_token: 'test-token-123' },
@@ -85,7 +87,75 @@ describe('getPreviewUtils', () => {
8587
);
8688
});
8789

88-
it('should append preview token to string URL', () => {
90+
it('should use url.default when item.Url is null', () => {
91+
const assetWithDefaultUrl: InferredContentReference = {
92+
url: {
93+
type: null,
94+
default: 'https://example.com/default-image.jpg',
95+
hierarchical: null,
96+
internal: null,
97+
graph: null,
98+
base: null,
99+
},
100+
item: {
101+
__typename: 'cmp_PublicImageAsset' as const,
102+
Url: null,
103+
Title: 'Test Image',
104+
AltText: 'Test alt text',
105+
Description: 'Test description',
106+
Renditions: [],
107+
FocalPoint: null,
108+
Tags: [],
109+
},
110+
};
111+
112+
const utils = getPreviewUtils({ __typename: 'TestPage' });
113+
const result = utils.src(assetWithDefaultUrl);
114+
115+
expect(result).toBe('https://example.com/default-image.jpg');
116+
});
117+
118+
it('should append preview token to url.default in preview mode', () => {
119+
const assetWithDefaultUrl: InferredContentReference = {
120+
url: {
121+
type: null,
122+
default: 'https://example.com/default-image.jpg',
123+
hierarchical: null,
124+
internal: null,
125+
graph: null,
126+
base: null,
127+
},
128+
item: {
129+
__typename: 'cmp_PublicImageAsset' as const,
130+
Url: null,
131+
Title: 'Test Image',
132+
AltText: 'Test alt text',
133+
Description: 'Test description',
134+
Renditions: [],
135+
FocalPoint: null,
136+
Tags: [],
137+
},
138+
};
139+
140+
const utils = getPreviewUtils({
141+
__typename: 'TestPage',
142+
__context: { edit: true, preview_token: 'test-token-456' },
143+
});
144+
const result = utils.src(assetWithDefaultUrl);
145+
146+
expect(result).toBe(
147+
'https://example.com/default-image.jpg?preview_token=test-token-456'
148+
);
149+
});
150+
151+
it('should handle string URL input', () => {
152+
const utils = getPreviewUtils({ __typename: 'TestPage' });
153+
const result = utils.src('https://example.com/image.jpg');
154+
155+
expect(result).toBe('https://example.com/image.jpg');
156+
});
157+
158+
it('should append preview token to string URL in preview mode', () => {
89159
const utils = getPreviewUtils({
90160
__typename: 'TestPage',
91161
__context: { edit: true, preview_token: 'test-token-123' },
@@ -97,12 +167,87 @@ describe('getPreviewUtils', () => {
97167
);
98168
});
99169

100-
it('should return empty string for string URL when not in preview mode', () => {
170+
it('should return empty string for null input', () => {
101171
const utils = getPreviewUtils({ __typename: 'TestPage' });
102-
const result = utils.src('https://example.com/image.jpg');
172+
const result = utils.src(null);
103173

104174
expect(result).toBe('');
105175
});
176+
177+
it('should return empty string for undefined input', () => {
178+
const utils = getPreviewUtils({ __typename: 'TestPage' });
179+
const result = utils.src(undefined);
180+
181+
expect(result).toBe('');
182+
});
183+
184+
it('should return empty string when asset has no URL', () => {
185+
const assetWithoutUrl: InferredContentReference = {
186+
url: {
187+
type: null,
188+
default: null,
189+
hierarchical: null,
190+
internal: null,
191+
graph: null,
192+
base: null,
193+
},
194+
item: {
195+
__typename: 'cmp_PublicImageAsset' as const,
196+
Url: null,
197+
Title: 'Test Image',
198+
AltText: 'Test alt text',
199+
Description: 'Test description',
200+
Renditions: [],
201+
FocalPoint: null,
202+
Tags: [],
203+
},
204+
};
205+
206+
const utils = getPreviewUtils({ __typename: 'TestPage' });
207+
const result = utils.src(assetWithoutUrl);
208+
209+
expect(result).toBe('');
210+
});
211+
212+
it('should handle URLs with existing query parameters', () => {
213+
const utils = getPreviewUtils({
214+
__typename: 'TestPage',
215+
__context: { edit: true, preview_token: 'test-token-123' },
216+
});
217+
const result = utils.src('https://example.com/image.jpg?width=500');
218+
219+
expect(result).toBe(
220+
'https://example.com/image.jpg?width=500&preview_token=test-token-123'
221+
);
222+
});
223+
224+
it('should prefer url.default over item.Url when both exist', () => {
225+
const assetWithBothUrls: InferredContentReference = {
226+
url: {
227+
type: null,
228+
default: 'https://example.com/default-url.jpg',
229+
hierarchical: null,
230+
internal: null,
231+
graph: null,
232+
base: null,
233+
},
234+
item: {
235+
__typename: 'cmp_PublicImageAsset' as const,
236+
Url: 'https://example.com/item-url.jpg',
237+
Title: 'Test Image',
238+
AltText: 'Test alt text',
239+
Description: 'Test description',
240+
Renditions: [],
241+
FocalPoint: null,
242+
Tags: [],
243+
},
244+
};
245+
246+
const utils = getPreviewUtils({ __typename: 'TestPage' });
247+
const result = utils.src(assetWithBothUrls);
248+
249+
expect(result).toBe('https://example.com/default-url.jpg');
250+
});
106251
});
107252

108253
describe('getSrcset()', () => {

packages/optimizely-cms-sdk/src/react/server.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,17 @@ export function getPreviewUtils(opti: OptimizelyComponentProps['opti']) {
343343
src(input: InferredContentReference | string | null | undefined): string {
344344
const previewToken = opti.__context?.preview_token;
345345

346-
// if input is a ContentReference
347-
if (typeof input === 'object' && previewToken && input?.item?.Url) {
348-
return appendToken(input?.item?.Url, previewToken);
346+
// if input is an object with a URL
347+
if (typeof input === 'object' && input) {
348+
// if dam asset is selected the default URL is in input.url.default will be null
349+
const url = input.url?.default ?? input.item?.Url;
350+
if (url) {
351+
return appendToken(url, previewToken);
352+
}
349353
}
350354

351355
// if input is a string URL
352-
if (typeof input === 'string' && previewToken) {
356+
if (typeof input === 'string') {
353357
return appendToken(input, previewToken);
354358
}
355359

packages/optimizely-cms-sdk/src/util/preview.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @returns The URL with the preview token appended as a query parameter.
88
*/
99
export const appendToken = (url: string, previewToken?: string): string => {
10-
if (!previewToken) return url;
10+
if (!previewToken || previewToken.trim() === '') return url;
1111
const separator = url.includes('?') ? '&' : '?';
1212
return `${url}${separator}preview_token=${previewToken}`;
1313
};

samples/nextjs-template/src/app/globals.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,6 @@ a:hover span.animate {
414414
.about-us .about-us-image {
415415
position: relative;
416416
width: 100%;
417-
padding-top: 56.25%;
418417
}
419418

420419
.about-us .about-us-image img {

0 commit comments

Comments
 (0)