diff --git a/packages/optimizely-cms-sdk/src/react/__test__/assetsUtils.test.tsx b/packages/optimizely-cms-sdk/src/react/__test__/assetsUtils.test.tsx index 4a07d2aa..af5120b3 100644 --- a/packages/optimizely-cms-sdk/src/react/__test__/assetsUtils.test.tsx +++ b/packages/optimizely-cms-sdk/src/react/__test__/assetsUtils.test.tsx @@ -65,14 +65,16 @@ describe('getPreviewUtils', () => { }; describe('src()', () => { - it('should return empty string when not in preview mode', () => { + it('should return item.Url when not in preview mode', () => { const utils = getPreviewUtils({ __typename: 'TestPage' }); const result = utils.src(mockImageAsset); - expect(result).toBe(''); + expect(result).toBe( + 'https://assets.local-cms.com/0a2f4b27-4f15-4bb9-ba14-d69b49ae5b85/cmp_73d48db0-2abe-4a33-91f5-94d0ac5e85e5.jpg' + ); }); - it('should append preview token to item URL', () => { + it('should append preview token to item.Url in preview mode', () => { const utils = getPreviewUtils({ __typename: 'TestPage', __context: { edit: true, preview_token: 'test-token-123' }, @@ -85,7 +87,75 @@ describe('getPreviewUtils', () => { ); }); - it('should append preview token to string URL', () => { + it('should use url.default when item.Url is null', () => { + const assetWithDefaultUrl: InferredContentReference = { + url: { + type: null, + default: 'https://example.com/default-image.jpg', + hierarchical: null, + internal: null, + graph: null, + base: null, + }, + item: { + __typename: 'cmp_PublicImageAsset' as const, + Url: null, + Title: 'Test Image', + AltText: 'Test alt text', + Description: 'Test description', + Renditions: [], + FocalPoint: null, + Tags: [], + }, + }; + + const utils = getPreviewUtils({ __typename: 'TestPage' }); + const result = utils.src(assetWithDefaultUrl); + + expect(result).toBe('https://example.com/default-image.jpg'); + }); + + it('should append preview token to url.default in preview mode', () => { + const assetWithDefaultUrl: InferredContentReference = { + url: { + type: null, + default: 'https://example.com/default-image.jpg', + hierarchical: null, + internal: null, + graph: null, + base: null, + }, + item: { + __typename: 'cmp_PublicImageAsset' as const, + Url: null, + Title: 'Test Image', + AltText: 'Test alt text', + Description: 'Test description', + Renditions: [], + FocalPoint: null, + Tags: [], + }, + }; + + const utils = getPreviewUtils({ + __typename: 'TestPage', + __context: { edit: true, preview_token: 'test-token-456' }, + }); + const result = utils.src(assetWithDefaultUrl); + + expect(result).toBe( + 'https://example.com/default-image.jpg?preview_token=test-token-456' + ); + }); + + it('should handle string URL input', () => { + const utils = getPreviewUtils({ __typename: 'TestPage' }); + const result = utils.src('https://example.com/image.jpg'); + + expect(result).toBe('https://example.com/image.jpg'); + }); + + it('should append preview token to string URL in preview mode', () => { const utils = getPreviewUtils({ __typename: 'TestPage', __context: { edit: true, preview_token: 'test-token-123' }, @@ -97,12 +167,87 @@ describe('getPreviewUtils', () => { ); }); - it('should return empty string for string URL when not in preview mode', () => { + it('should return empty string for null input', () => { const utils = getPreviewUtils({ __typename: 'TestPage' }); - const result = utils.src('https://example.com/image.jpg'); + const result = utils.src(null); expect(result).toBe(''); }); + + it('should return empty string for undefined input', () => { + const utils = getPreviewUtils({ __typename: 'TestPage' }); + const result = utils.src(undefined); + + expect(result).toBe(''); + }); + + it('should return empty string when asset has no URL', () => { + const assetWithoutUrl: InferredContentReference = { + url: { + type: null, + default: null, + hierarchical: null, + internal: null, + graph: null, + base: null, + }, + item: { + __typename: 'cmp_PublicImageAsset' as const, + Url: null, + Title: 'Test Image', + AltText: 'Test alt text', + Description: 'Test description', + Renditions: [], + FocalPoint: null, + Tags: [], + }, + }; + + const utils = getPreviewUtils({ __typename: 'TestPage' }); + const result = utils.src(assetWithoutUrl); + + expect(result).toBe(''); + }); + + it('should handle URLs with existing query parameters', () => { + const utils = getPreviewUtils({ + __typename: 'TestPage', + __context: { edit: true, preview_token: 'test-token-123' }, + }); + const result = utils.src('https://example.com/image.jpg?width=500'); + + expect(result).toBe( + 'https://example.com/image.jpg?width=500&preview_token=test-token-123' + ); + }); + + it('should prefer url.default over item.Url when both exist', () => { + const assetWithBothUrls: InferredContentReference = { + url: { + type: null, + default: 'https://example.com/default-url.jpg', + hierarchical: null, + internal: null, + graph: null, + base: null, + }, + item: { + __typename: 'cmp_PublicImageAsset' as const, + Url: 'https://example.com/item-url.jpg', + Title: 'Test Image', + AltText: 'Test alt text', + Description: 'Test description', + Renditions: [], + FocalPoint: null, + Tags: [], + }, + }; + + const utils = getPreviewUtils({ __typename: 'TestPage' }); + const result = utils.src(assetWithBothUrls); + + expect(result).toBe('https://example.com/default-url.jpg'); + }); }); describe('getSrcset()', () => { diff --git a/packages/optimizely-cms-sdk/src/react/server.tsx b/packages/optimizely-cms-sdk/src/react/server.tsx index bb64a54e..251be4d2 100644 --- a/packages/optimizely-cms-sdk/src/react/server.tsx +++ b/packages/optimizely-cms-sdk/src/react/server.tsx @@ -343,13 +343,17 @@ export function getPreviewUtils(opti: OptimizelyComponentProps['opti']) { src(input: InferredContentReference | string | null | undefined): string { const previewToken = opti.__context?.preview_token; - // if input is a ContentReference - if (typeof input === 'object' && previewToken && input?.item?.Url) { - return appendToken(input?.item?.Url, previewToken); + // if input is an object with a URL + if (typeof input === 'object' && input) { + // if dam asset is selected the default URL is in input.url.default will be null + const url = input.url?.default ?? input.item?.Url; + if (url) { + return appendToken(url, previewToken); + } } // if input is a string URL - if (typeof input === 'string' && previewToken) { + if (typeof input === 'string') { return appendToken(input, previewToken); } diff --git a/packages/optimizely-cms-sdk/src/util/preview.ts b/packages/optimizely-cms-sdk/src/util/preview.ts index 6d0e9566..ebdd0340 100644 --- a/packages/optimizely-cms-sdk/src/util/preview.ts +++ b/packages/optimizely-cms-sdk/src/util/preview.ts @@ -7,7 +7,7 @@ * @returns The URL with the preview token appended as a query parameter. */ export const appendToken = (url: string, previewToken?: string): string => { - if (!previewToken) return url; + if (!previewToken || previewToken.trim() === '') return url; const separator = url.includes('?') ? '&' : '?'; return `${url}${separator}preview_token=${previewToken}`; }; diff --git a/samples/nextjs-template/src/app/globals.css b/samples/nextjs-template/src/app/globals.css index 049fa29b..e2eb7456 100644 --- a/samples/nextjs-template/src/app/globals.css +++ b/samples/nextjs-template/src/app/globals.css @@ -414,7 +414,6 @@ a:hover span.animate { .about-us .about-us-image { position: relative; width: 100%; - padding-top: 56.25%; } .about-us .about-us-image img {