countly-sdk-web 25.4.3 → 25.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 25.4.4
2
+
3
+ - Improved user property recording order with respect to sessions and events.
4
+
1
5
  ## 25.4.3
2
6
 
3
7
  - Added filtering capability to `content` interface through `enterContentZone(contentFilterCallback)`.
@@ -15,7 +15,7 @@ function initMain(name, version) {
15
15
  }
16
16
 
17
17
  const SDK_NAME = "javascript_native_web";
18
- const SDK_VERSION = "25.4.3";
18
+ const SDK_VERSION = "25.4.4";
19
19
 
20
20
  // tests
21
21
  describe("Bridged SDK Utilities Tests", () => {
@@ -0,0 +1,139 @@
1
+ /* eslint-disable cypress/no-unnecessary-waiting */
2
+ /* eslint-disable require-jsdoc */
3
+ var Countly = require("../../lib/countly");
4
+ var hp = require("../support/helper");
5
+
6
+ Countly.q = Countly.q || [];
7
+
8
+ function initMain() {
9
+ Countly.init({
10
+ app_key: "YOUR_APP_KEY",
11
+ url: "https://your.domain.count.ly",
12
+ test_mode_eq: true,
13
+ test_mode: true
14
+ });
15
+ }
16
+
17
+ const userDetailObj = hp.userDetailObj;
18
+
19
+ // an event object to use
20
+ const eventObj = {
21
+ key: "in_app_purchase",
22
+ count: 3,
23
+ sum: 2.97,
24
+ dur: 300,
25
+ segmentation: {
26
+ app_version: "1.0",
27
+ country: "Tahiti"
28
+ }
29
+ };
30
+ const custUP = {
31
+ custom: { "name": "John Doe"}
32
+ }
33
+
34
+ describe("User properties order test", () => {
35
+ it("User details order test", () => {
36
+ hp.haltAndClearStorage(() => {
37
+ initMain();
38
+ Countly.begin_session();
39
+ Countly.add_event(eventObj);
40
+ Countly.user_details(userDetailObj);
41
+ Countly.add_event(eventObj);
42
+ Countly.add_event(eventObj);
43
+ Countly.user_details(userDetailObj);
44
+ cy.fetch_local_event_queue().then((eq) => {
45
+ expect(eq.length).to.equal(0);
46
+ });
47
+ cy.wait(500).then(() => {
48
+ cy.fetch_local_request_queue(hp.appKey).then((rq) => {
49
+ expect(rq.length).to.equal(5);
50
+ cy.log(rq);
51
+ cy.check_session(rq[0]);
52
+ cy.check_event(JSON.parse(rq[1].events)[1], eventObj, undefined, false);
53
+ cy.check_user_details(rq[2], userDetailObj);
54
+ cy.check_event(JSON.parse(rq[3].events)[0], eventObj, undefined, false);
55
+ cy.check_event(JSON.parse(rq[3].events)[1], eventObj, undefined, false);
56
+ cy.check_user_details(rq[4], userDetailObj);
57
+ });
58
+ });
59
+ });
60
+ });
61
+ it("User details order test, async", () => {
62
+ hp.haltAndClearStorage(() => {
63
+ initMain();
64
+ Countly.q.push(['track_sessions']);
65
+ Countly.q.push(['add_event', eventObj]);
66
+ Countly.q.push(['user_details', userDetailObj]);
67
+ Countly.q.push(['add_event', eventObj]);
68
+ Countly.q.push(['add_event', eventObj]);
69
+ Countly.q.push(['user_details', userDetailObj]);
70
+ cy.fetch_local_event_queue().then((eq) => {
71
+ expect(eq.length).to.equal(0);
72
+ });
73
+ cy.wait(500).then(() => {
74
+ cy.fetch_local_request_queue(hp.appKey).then((rq) => {
75
+ expect(rq.length).to.equal(5);
76
+ cy.log(rq);
77
+ cy.check_session(rq[0]);
78
+ cy.check_event(JSON.parse(rq[1].events)[1], eventObj, undefined, false);
79
+ cy.check_user_details(rq[2], userDetailObj);
80
+ cy.check_event(JSON.parse(rq[3].events)[0], eventObj, undefined, false);
81
+ cy.check_event(JSON.parse(rq[3].events)[1], eventObj, undefined, false);
82
+ cy.check_user_details(rq[4], userDetailObj);
83
+ });
84
+ });
85
+ });
86
+ });
87
+ it("User data order test", () => {
88
+ hp.haltAndClearStorage(() => {
89
+ initMain();
90
+ Countly.userData.set("name", "John Doe");
91
+ Countly.begin_session();
92
+ Countly.userData.set("name", "John Doe");
93
+ Countly.add_event(eventObj);
94
+ Countly.userData.set("name", "John Doe");
95
+ Countly.user_details(userDetailObj);
96
+ cy.fetch_local_event_queue().then((eq) => {
97
+ expect(eq.length).to.equal(0);
98
+ });
99
+ cy.wait(500).then(() => {
100
+ cy.fetch_local_request_queue(hp.appKey).then((rq) => {
101
+ expect(rq.length).to.equal(6);
102
+ cy.log(rq);
103
+ cy.check_user_details(rq[0], custUP);
104
+ cy.check_session(rq[1]);
105
+ cy.check_user_details(rq[2], custUP);
106
+ cy.check_event(JSON.parse(rq[3].events)[1], eventObj, undefined, false);
107
+ cy.check_user_details(rq[4], custUP);
108
+ cy.check_user_details(rq[5], userDetailObj);
109
+ });
110
+ });
111
+ });
112
+ });
113
+ it("User data order test, async", () => {
114
+ hp.haltAndClearStorage(() => {
115
+ initMain();
116
+ Countly.q.push(['userData.set', "name", "John Doe"]);
117
+ Countly.q.push(['track_sessions']);
118
+ Countly.q.push(['userData.set', "name", "John Doe"]);
119
+ Countly.q.push(['add_event', eventObj]);
120
+ Countly.q.push(['userData.set', "name", "John Doe"]);
121
+ Countly.q.push(['user_details', userDetailObj]);
122
+ cy.fetch_local_event_queue().then((eq) => {
123
+ expect(eq.length).to.equal(0);
124
+ });
125
+ cy.wait(500).then(() => {
126
+ cy.fetch_local_request_queue(hp.appKey).then((rq) => {
127
+ expect(rq.length).to.equal(6);
128
+ cy.log(rq);
129
+ cy.check_user_details(rq[0], custUP);
130
+ cy.check_session(rq[1]);
131
+ cy.check_user_details(rq[2], custUP);
132
+ cy.check_event(JSON.parse(rq[3].events)[1], eventObj, undefined, false);
133
+ cy.check_user_details(rq[4], custUP);
134
+ cy.check_user_details(rq[5], userDetailObj);
135
+ });
136
+ });
137
+ });
138
+ });
139
+ });
package/lib/countly.js CHANGED
@@ -217,7 +217,7 @@
217
217
  backoffCount: "cly_hc_backoff_count",
218
218
  consecutiveBackoffCount: "cly_hc_consecutive_backoff_count"
219
219
  });
220
- var SDK_VERSION = "25.4.3";
220
+ var SDK_VERSION = "25.4.4";
221
221
  var SDK_NAME = "javascript_native_web";
222
222
 
223
223
  // Using this on document.referrer would return an array with 17 elements in it. The 12th element (array[11]) would be the path we are looking for. Others would be things like password and such (use https://regex101.com/ to check more)
@@ -945,6 +945,7 @@
945
945
  var _testModeTime = /*#__PURE__*/new WeakMap();
946
946
  var _requestTimeoutDuration = /*#__PURE__*/new WeakMap();
947
947
  var _contentFilterCallback = /*#__PURE__*/new WeakMap();
948
+ var _isProcessingAsyncFromUserDataSave = /*#__PURE__*/new WeakMap();
948
949
  var _getAndSetServerConfig = /*#__PURE__*/new WeakMap();
949
950
  var _populateServerConfig = /*#__PURE__*/new WeakMap();
950
951
  var _initialize = /*#__PURE__*/new WeakMap();
@@ -1101,6 +1102,7 @@
1101
1102
  _classPrivateFieldInitSpec(this, _testModeTime, void 0);
1102
1103
  _classPrivateFieldInitSpec(this, _requestTimeoutDuration, void 0);
1103
1104
  _classPrivateFieldInitSpec(this, _contentFilterCallback, void 0);
1105
+ _classPrivateFieldInitSpec(this, _isProcessingAsyncFromUserDataSave, void 0);
1104
1106
  _classPrivateFieldInitSpec(this, _getAndSetServerConfig, function () {
1105
1107
  if (_this.device_id === "[CLY]_temp_id") {
1106
1108
  _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "server_config, Device ID is temporary, not fetching server config");
@@ -2059,6 +2061,7 @@
2059
2061
  var req = {};
2060
2062
  req.begin_session = 1;
2061
2063
  req.metrics = JSON.stringify(_classPrivateFieldGet2(_getMetrics, _this).call(_this));
2064
+ _this.userData.save(true); // ensure user data is saved before session start
2062
2065
  _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, req);
2063
2066
  }
2064
2067
  _classPrivateFieldGet2(_setValueInStorage, _this).call(_this, "cly_session", getTimestamp() + _classPrivateFieldGet2(_sessionCookieTimeout, _this) * 60);
@@ -2085,6 +2088,7 @@
2085
2088
  return;
2086
2089
  }
2087
2090
  _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "session_duration, Session extended: [" + sec + "]");
2091
+ _this.userData.save(true); // ensure user data is saved before session update
2088
2092
  _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, {
2089
2093
  session_duration: sec
2090
2094
  });
@@ -2107,6 +2111,7 @@
2107
2111
  _classPrivateFieldGet2(_reportViewDuration, _this).call(_this);
2108
2112
  if (!_classPrivateFieldGet2(_useSessionCookie, _this) || force) {
2109
2113
  _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "end_session, Session ended");
2114
+ _this.userData.save(true); // ensure user data is saved before session end
2110
2115
  _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, {
2111
2116
  end_session: 1,
2112
2117
  session_duration: sec
@@ -2267,6 +2272,9 @@
2267
2272
  _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.ERROR, "Adding event failed. Event must have a key property");
2268
2273
  return;
2269
2274
  }
2275
+ if (!_classPrivateFieldGet2(_isProcessingAsyncFromUserDataSave, _this)) {
2276
+ _this.userData.save(true); // ensure cached user data is saved before adding event
2277
+ }
2270
2278
  if (!event.count) {
2271
2279
  event.count = 1;
2272
2280
  }
@@ -2441,6 +2449,7 @@
2441
2449
  user.byear = truncateSingleValue(user.byear, _classPrivateFieldGet2(_SCLimitValueSize, _this), "user_details", _classPrivateFieldGet2(_log, _this));
2442
2450
  user.custom = truncateObject(user.custom, _classPrivateFieldGet2(_SCLimitKeyLength, _this), _classPrivateFieldGet2(_SCLimitValueSize, _this), _classPrivateFieldGet2(_SCLimitSegmentationValues, _this), "user_details", _classPrivateFieldGet2(_log, _this));
2443
2451
  var props = ["name", "username", "email", "organization", "phone", "picture", "gender", "byear", "custom"];
2452
+ _this.userData.save(); // ensure user data (and events) is saved before sending user details
2444
2453
  _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, {
2445
2454
  user_details: JSON.stringify(createNewObjectFromProperties(user, props))
2446
2455
  });
@@ -2627,20 +2636,30 @@
2627
2636
  * Save changes made to user's custom properties object and send them to server
2628
2637
  * @memberof Countly.userData
2629
2638
  * */
2630
- save: function save() {
2631
- _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] save, Saving changes to user's custom property");
2632
- if (_this.check_consent(featureEnums.USERS)) {
2633
- // process async queue before sending events
2634
- _classPrivateFieldGet2(_processAsyncQueue, _this).call(_this);
2635
- // flush events to event queue to prevent a drill issue
2639
+ save: function save(forEvents) {
2640
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] save, Saving changes to user's custom property. forEvents:[" + forEvents + "]");
2641
+ if (!_this.check_consent(featureEnums.USERS) || Object.keys(_classPrivateFieldGet2(_customData, _this)).length === 0) {
2642
+ return;
2643
+ }
2644
+ if (!forEvents) {
2645
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "[userData] save, flushing async queue and event queue before sending custom user data");
2646
+ _classPrivateFieldSet2(_isProcessingAsyncFromUserDataSave, _this, true);
2647
+ try {
2648
+ // process async queue before sending events
2649
+ _classPrivateFieldGet2(_processAsyncQueue, _this).call(_this);
2650
+ } finally {
2651
+ _classPrivateFieldSet2(_isProcessingAsyncFromUserDataSave, _this, false);
2652
+ }
2653
+
2654
+ // flush events to request queue
2636
2655
  _classPrivateFieldGet2(_sendEventsForced, _this).call(_this);
2637
- _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "user_details, flushed the event queue");
2638
- _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, {
2639
- user_details: JSON.stringify({
2640
- custom: _classPrivateFieldGet2(_customData, _this)
2641
- })
2642
- });
2643
2656
  }
2657
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.INFO, "[userData] save, will send the following custom data to server: [" + JSON.stringify(_classPrivateFieldGet2(_customData, _this)) + "]");
2658
+ _classPrivateFieldGet2(_toRequestQueue, _this).call(_this, {
2659
+ user_details: JSON.stringify({
2660
+ custom: _classPrivateFieldGet2(_customData, _this)
2661
+ })
2662
+ });
2644
2663
  _classPrivateFieldSet2(_customData, _this, {});
2645
2664
  }
2646
2665
  });
@@ -6516,6 +6535,7 @@
6516
6535
  _classPrivateFieldSet2(_SCBackoffDuration, this, 60); // 60 seconds
6517
6536
  _classPrivateFieldSet2(_requestTimeoutDuration, this, 30000); // 30 seconds
6518
6537
  _classPrivateFieldSet2(_contentFilterCallback, this, null);
6538
+ _classPrivateFieldSet2(_isProcessingAsyncFromUserDataSave, this, false);
6519
6539
  this.app_key = getConfig("app_key", _ob, null);
6520
6540
  this.url = stripTrailingSlash(getConfig("url", _ob, ""));
6521
6541
  this.serialize = getConfig("serialize", _ob, Countly.serialize);