Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,28 @@ describe('CloudinaryImageComponent render', () => {
tick(0);
const imgElement: HTMLImageElement = fixture.nativeElement;
const img = imgElement.querySelector('img');
expect(img.outerHTML).toBe('<img _ngcontent-a-c11="" alt="text text text" width="400px" height="500px"' +
' loading="eager" src="https://res.cloudinary.com/demo/image/upload/sample">');
expect(img.getAttribute('alt')).toBe('text text text');
expect(img.getAttribute('width')).toBe('400px');
expect(img.getAttribute('height')).toBe('500px');
expect(img.getAttribute('loading')).toBe('eager');
expect(img.src).toBe('https://res.cloudinary.com/demo/image/upload/sample');
component.width = '800px';
component.alt = 'updated alt text';
component.height = '1000px';
component.loading = 'lazy';
component.ngOnChanges();
expect(img.outerHTML).toBe('<img _ngcontent-a-c11="" alt="updated alt text" width="800px" height="1000px"' +
' loading="lazy" src="https://res.cloudinary.com/demo/image/upload/sample">');
expect(img.getAttribute('alt')).toBe('updated alt text');
expect(img.getAttribute('width')).toBe('800px');
expect(img.getAttribute('height')).toBe('1000px');
expect(img.getAttribute('loading')).toBe('lazy');
expect(img.src).toBe('https://res.cloudinary.com/demo/image/upload/sample');
component.width = undefined;
component.height = undefined;
component.alt = '';
component.loading = 'lazy';
component.ngOnChanges();
expect(img.outerHTML).toBe('<img _ngcontent-a-c11="" alt=""' +
' loading="lazy" src="https://res.cloudinary.com/demo/image/upload/sample">');
expect(img.getAttribute('alt')).toBe('');
expect(img.getAttribute('loading')).toBe('lazy');
expect(img.src).toBe('https://res.cloudinary.com/demo/image/upload/sample');
}));
});
2 changes: 1 addition & 1 deletion packages/html/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type PictureSources = {minWidth?: number, maxWidth?: number, image: Cloud

export type PictureSource = {minWidth?: number, maxWidth?: number, image: CloudinaryImage, sizes?: string};

export type BaseAnalyticsOptions = {sdkSemver: string, techVersion: string, sdkCode: string};
export type BaseAnalyticsOptions = {sdkSemver: string, techVersion: string, sdkCode: string, product?: string};

export type AnalyticsOptions = Parameters<CloudinaryImage['toURL']>[0];

Expand Down
1 change: 1 addition & 0 deletions packages/html/src/utils/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const getAnalyticsOptions = (options?: BaseAnalyticsOptions, features: vo
sdkCode: options.sdkCode,
sdkSemver: options.sdkSemver,
techVersion: options.techVersion,
...(options.product !== undefined && { product: options.product }),
...features
}
} : null
Expand Down
37 changes: 37 additions & 0 deletions packages/react/__tests__/analytics.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,40 @@ describe('analytics', () => {
}, 0);// one tick
});
});

describe('analytics when created via CLI', () => {
let AdvancedImageCLI: typeof AdvancedImage;
let CloudinaryImageCLI: typeof CloudinaryImage;

beforeAll(() => {
process.env.CLOUDINARY_SOURCE = 'cli';
jest.resetModules();
const src = require('../src');
const constants = require('../src/internal/SDKAnalyticsConstants');
AdvancedImageCLI = src.AdvancedImage;
CloudinaryImageCLI = require('@cloudinary/url-gen/assets/CloudinaryImage').CloudinaryImage;
const SDKAnalyticsConstantsCLI = constants.SDKAnalyticsConstants;
SDKAnalyticsConstantsCLI.sdkSemver = '1.0.0';
SDKAnalyticsConstantsCLI.techVersion = '10.2.5';
});

afterAll(() => {
delete process.env.CLOUDINARY_SOURCE;
jest.resetModules();
});

it('generates analytics with Product B (Integrations) and sdkCode H (React CLI)', function (done) {
const cldImg = new CloudinaryImageCLI('sample', { cloudName: 'demo' });
const component = mount(<AdvancedImageCLI cldImg={cldImg} />);
setTimeout(() => {
const html = component.html();
const match = html.match(/_a=([A-Za-z0-9]+)/);
expect(match).toBeTruthy();
const token = match![1];
// Algorithm B: 1st = algo, 2nd = product (B = Integrations), 3rd = sdkCode (H = React CLI)
expect(token[1]).toBe('B');
expect(token[2]).toBe('H');
done();
}, 0);
});
});
14 changes: 13 additions & 1 deletion packages/react/src/internal/SDKAnalyticsConstants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import React from 'react'

// Detect if this project was created via create-cloudinary-react CLI (Integrations)
function isCLI(): boolean {
if (typeof process !== 'undefined' && process.env) {
return process.env.CLOUDINARY_SOURCE === 'cli' || process.env.CLD_CLI === 'true';
}
return false;
}

// When CLI: use Algorithm B with Product B (Integrations) and sdkCode H (React CLI). Otherwise React SDK: sdkCode J.
const isCLIDetected = isCLI();

export const SDKAnalyticsConstants = {
sdkSemver: 'PACKAGE_VERSION_INJECTED_DURING_BUILD',
techVersion: React.version,
sdkCode: 'J'
sdkCode: isCLIDetected ? 'H' : 'J',
...(isCLIDetected && { product: 'B' as const })
};
Loading