Skip to content

Commit 00a8eb2

Browse files
authored
Add react cli analytics (#264)
* feat(analytics): add CLI feature detection for React SDK --------- Co-authored-by: strausr <git config --global user.email>
1 parent d3def8e commit 00a8eb2

File tree

5 files changed

+65
-8
lines changed

5 files changed

+65
-8
lines changed

packages/angular/projects/cloudinary-library/src/tests/cloudinary-image.component.spec.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,28 @@ describe('CloudinaryImageComponent render', () => {
5252
tick(0);
5353
const imgElement: HTMLImageElement = fixture.nativeElement;
5454
const img = imgElement.querySelector('img');
55-
expect(img.outerHTML).toBe('<img _ngcontent-a-c11="" alt="text text text" width="400px" height="500px"' +
56-
' loading="eager" src="https://res.cloudinary.com/demo/image/upload/sample">');
55+
expect(img.getAttribute('alt')).toBe('text text text');
56+
expect(img.getAttribute('width')).toBe('400px');
57+
expect(img.getAttribute('height')).toBe('500px');
58+
expect(img.getAttribute('loading')).toBe('eager');
59+
expect(img.src).toBe('https://res.cloudinary.com/demo/image/upload/sample');
5760
component.width = '800px';
5861
component.alt = 'updated alt text';
5962
component.height = '1000px';
6063
component.loading = 'lazy';
6164
component.ngOnChanges();
62-
expect(img.outerHTML).toBe('<img _ngcontent-a-c11="" alt="updated alt text" width="800px" height="1000px"' +
63-
' loading="lazy" src="https://res.cloudinary.com/demo/image/upload/sample">');
65+
expect(img.getAttribute('alt')).toBe('updated alt text');
66+
expect(img.getAttribute('width')).toBe('800px');
67+
expect(img.getAttribute('height')).toBe('1000px');
68+
expect(img.getAttribute('loading')).toBe('lazy');
69+
expect(img.src).toBe('https://res.cloudinary.com/demo/image/upload/sample');
6470
component.width = undefined;
6571
component.height = undefined;
6672
component.alt = '';
6773
component.loading = 'lazy';
6874
component.ngOnChanges();
69-
expect(img.outerHTML).toBe('<img _ngcontent-a-c11="" alt=""' +
70-
' loading="lazy" src="https://res.cloudinary.com/demo/image/upload/sample">');
75+
expect(img.getAttribute('alt')).toBe('');
76+
expect(img.getAttribute('loading')).toBe('lazy');
77+
expect(img.src).toBe('https://res.cloudinary.com/demo/image/upload/sample');
7178
}));
7279
});

packages/html/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export type PictureSources = {minWidth?: number, maxWidth?: number, image: Cloud
2424

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

27-
export type BaseAnalyticsOptions = {sdkSemver: string, techVersion: string, sdkCode: string};
27+
export type BaseAnalyticsOptions = {sdkSemver: string, techVersion: string, sdkCode: string, product?: string};
2828

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

packages/html/src/utils/analytics.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const getAnalyticsOptions = (options?: BaseAnalyticsOptions, features: vo
66
sdkCode: options.sdkCode,
77
sdkSemver: options.sdkSemver,
88
techVersion: options.techVersion,
9+
...(options.product !== undefined && { product: options.product }),
910
...features
1011
}
1112
} : null

packages/react/__tests__/analytics.test.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,40 @@ describe('analytics', () => {
2626
}, 0);// one tick
2727
});
2828
});
29+
30+
describe('analytics when created via CLI', () => {
31+
let AdvancedImageCLI: typeof AdvancedImage;
32+
let CloudinaryImageCLI: typeof CloudinaryImage;
33+
34+
beforeAll(() => {
35+
process.env.CLOUDINARY_SOURCE = 'cli';
36+
jest.resetModules();
37+
const src = require('../src');
38+
const constants = require('../src/internal/SDKAnalyticsConstants');
39+
AdvancedImageCLI = src.AdvancedImage;
40+
CloudinaryImageCLI = require('@cloudinary/url-gen/assets/CloudinaryImage').CloudinaryImage;
41+
const SDKAnalyticsConstantsCLI = constants.SDKAnalyticsConstants;
42+
SDKAnalyticsConstantsCLI.sdkSemver = '1.0.0';
43+
SDKAnalyticsConstantsCLI.techVersion = '10.2.5';
44+
});
45+
46+
afterAll(() => {
47+
delete process.env.CLOUDINARY_SOURCE;
48+
jest.resetModules();
49+
});
50+
51+
it('generates analytics with Product B (Integrations) and sdkCode H (React CLI)', function (done) {
52+
const cldImg = new CloudinaryImageCLI('sample', { cloudName: 'demo' });
53+
const component = mount(<AdvancedImageCLI cldImg={cldImg} />);
54+
setTimeout(() => {
55+
const html = component.html();
56+
const match = html.match(/_a=([A-Za-z0-9]+)/);
57+
expect(match).toBeTruthy();
58+
const token = match![1];
59+
// Algorithm B: 1st = algo, 2nd = product (B = Integrations), 3rd = sdkCode (H = React CLI)
60+
expect(token[1]).toBe('B');
61+
expect(token[2]).toBe('H');
62+
done();
63+
}, 0);
64+
});
65+
});
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
import React from 'react'
22

3+
// Detect if this project was created via create-cloudinary-react CLI (Integrations)
4+
function isCLI(): boolean {
5+
if (typeof process !== 'undefined' && process.env) {
6+
return process.env.CLOUDINARY_SOURCE === 'cli' || process.env.CLD_CLI === 'true';
7+
}
8+
return false;
9+
}
10+
11+
// When CLI: use Algorithm B with Product B (Integrations) and sdkCode H (React CLI). Otherwise React SDK: sdkCode J.
12+
const isCLIDetected = isCLI();
13+
314
export const SDKAnalyticsConstants = {
415
sdkSemver: 'PACKAGE_VERSION_INJECTED_DURING_BUILD',
516
techVersion: React.version,
6-
sdkCode: 'J'
17+
sdkCode: isCLIDetected ? 'H' : 'J',
18+
...(isCLIDetected && { product: 'B' as const })
719
};

0 commit comments

Comments
 (0)