Skip to content

Commit ef55592

Browse files
authored
Merge pull request #610 from Countly/26-new-version
Version 26.1.0
2 parents 4dcafe2 + 0d90d89 commit ef55592

12 files changed

Lines changed: 1950 additions & 316 deletions

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## 26.1.0
2+
3+
- Added support for SBS flags:
4+
- Event whitelisting / blacklisting
5+
- Segmentation whitelisting / blacklisting (global and per-event)
6+
- User property whitelisting / blacklisting
7+
- Journey trigger events
8+
- Added support for Feedback Widget resizing logic (will need server update to benefit.)
9+
- Improved testing consistency of queuing system
10+
11+
- Mitigated an issue where an unintended URL was opened when closing a feedback widget after a content block was closed.
12+
113
## 25.4.5
214

315
- Added SDK info methods:

cypress/e2e/behavior_settings.cy.js

Lines changed: 578 additions & 0 deletions
Large diffs are not rendered by default.

cypress/e2e/bridged_utils.cy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function initMain(name, version) {
1515
}
1616

1717
const SDK_NAME = "javascript_native_web";
18-
const SDK_VERSION = "25.4.5";
18+
const SDK_VERSION = "26.1.0";
1919

2020
// tests
2121
describe("Bridged SDK Utilities Tests", () => {
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/* eslint-disable require-jsdoc */
2+
var Countly = require("../../lib/countly");
3+
var hp = require("../support/helper");
4+
5+
/**
6+
* Tests for the fake_request_handler feature
7+
* This allows injecting a mock server in tests for controlled request/response handling
8+
*/
9+
describe("Fake request handler", () => {
10+
it("captures requests and provides custom responses via init config", () => {
11+
hp.haltAndClearStorage(() => {
12+
var capturedRequests = [];
13+
14+
Countly.init({
15+
app_key: hp.appKey,
16+
url: "https://test.count.ly",
17+
debug: true,
18+
fake_request_handler: function(req) {
19+
capturedRequests.push(req);
20+
// Return success response
21+
return { status: 200, responseText: '{"result":"Success"}' };
22+
}
23+
});
24+
25+
Countly.add_event({ key: "test_event", count: 1 });
26+
Countly.begin_session();
27+
28+
cy.wait(500).then(() => {
29+
// Verify requests were captured
30+
expect(capturedRequests.length).to.be.greaterThan(0);
31+
32+
// Check that we have different request types
33+
var functionNames = capturedRequests.map(r => r.functionName);
34+
expect(functionNames).to.include("send_request_queue");
35+
36+
// Verify request structure
37+
var hasBeginSession = capturedRequests.some(r =>
38+
r.params && r.params.begin_session === 1
39+
);
40+
expect(hasBeginSession).to.be.true;
41+
});
42+
});
43+
});
44+
45+
it("allows simulating error responses", () => {
46+
hp.haltAndClearStorage(() => {
47+
var requestCount = 0;
48+
49+
Countly.init({
50+
app_key: hp.appKey,
51+
url: "https://test.count.ly",
52+
debug: true,
53+
fake_request_handler: function() {
54+
requestCount++;
55+
// Simulate server error
56+
return { status: 500, responseText: 'Internal Server Error' };
57+
}
58+
});
59+
60+
Countly.begin_session();
61+
62+
cy.wait(300).then(() => {
63+
// Requests should still be captured even on error
64+
expect(requestCount).to.be.greaterThan(0);
65+
});
66+
});
67+
});
68+
69+
it("can be set at runtime via _internals", () => {
70+
hp.haltAndClearStorage(() => {
71+
var capturedRequests = [];
72+
73+
Countly.init({
74+
app_key: hp.appKey,
75+
url: "https://test.count.ly",
76+
debug: true,
77+
test_mode: true // prevent queue processing initially
78+
});
79+
80+
// Set handler at runtime
81+
Countly._internals.setFakeRequestHandler(function(req) {
82+
capturedRequests.push(req);
83+
return { status: 200, responseText: '{"result":"Success"}' };
84+
});
85+
86+
// Verify it was set
87+
var handler = Countly._internals.getFakeRequestHandler();
88+
expect(handler).to.be.a("function");
89+
90+
// Enable request processing
91+
Countly.test_mode_rq(false);
92+
93+
Countly.add_event({ key: "runtime_event", count: 1 });
94+
95+
cy.wait(500).then(() => {
96+
expect(capturedRequests.length).to.be.greaterThan(0);
97+
});
98+
});
99+
});
100+
101+
it("returns default success when handler returns undefined", () => {
102+
hp.haltAndClearStorage(() => {
103+
Countly.init({
104+
app_key: hp.appKey,
105+
url: "https://test.count.ly",
106+
debug: true,
107+
fake_request_handler: function() {
108+
// Return nothing - should default to success
109+
return undefined;
110+
}
111+
});
112+
113+
Countly.begin_session();
114+
115+
cy.wait(300).then(() => {
116+
// Session should start successfully with default response
117+
expect(Countly._internals.testingGetRequests().length).to.be.greaterThan(0);
118+
});
119+
});
120+
});
121+
122+
it("skips callback when handler returns false", () => {
123+
hp.haltAndClearStorage(() => {
124+
var capturedRequests = [];
125+
126+
Countly.init({
127+
app_key: hp.appKey,
128+
url: "https://test.count.ly",
129+
debug: true,
130+
fake_request_handler: function(req) {
131+
capturedRequests.push(req);
132+
// Return false to skip callback entirely
133+
return false;
134+
}
135+
});
136+
137+
Countly.begin_session();
138+
139+
cy.wait(300).then(() => {
140+
// Requests should still be captured
141+
expect(capturedRequests.length).to.be.greaterThan(0);
142+
});
143+
});
144+
});
145+
146+
it("works with helper createFakeRequestHandler utility", () => {
147+
hp.haltAndClearStorage(() => {
148+
// Use the helper utility for cleaner test setup
149+
var fakeServer = hp.createFakeRequestHandler({
150+
onRequest: function(req) {
151+
// Custom logic per request
152+
if (req.params && req.params.begin_session) {
153+
return { status: 200, responseText: '{"result":"Session started"}' };
154+
}
155+
return { status: 200, responseText: '{"result":"OK"}' };
156+
}
157+
});
158+
159+
Countly.init({
160+
app_key: hp.appKey,
161+
url: "https://test.count.ly",
162+
debug: true,
163+
fake_request_handler: fakeServer.handler
164+
});
165+
166+
Countly.begin_session();
167+
Countly.add_event({ key: "helper_event", count: 1 });
168+
169+
cy.wait(500).then(() => {
170+
// Use helper methods for easy querying
171+
var sessionReqs = fakeServer.findByParam("begin_session", 1);
172+
expect(sessionReqs.length).to.equal(1);
173+
174+
var allReqs = fakeServer.getRequests();
175+
expect(allReqs.length).to.be.greaterThan(0);
176+
177+
// Clear for next test section
178+
fakeServer.clear();
179+
expect(fakeServer.getRequests().length).to.equal(0);
180+
});
181+
});
182+
});
183+
184+
it("provides full request details for validation", () => {
185+
hp.haltAndClearStorage(() => {
186+
var lastRequest = null;
187+
188+
Countly.init({
189+
app_key: hp.appKey,
190+
url: "https://test.count.ly",
191+
debug: true,
192+
fake_request_handler: function(req) {
193+
lastRequest = req;
194+
return { status: 200, responseText: '{"result":"Success"}' };
195+
}
196+
});
197+
198+
Countly.begin_session();
199+
200+
cy.wait(300).then(() => {
201+
expect(lastRequest).to.not.be.null;
202+
203+
// Verify request structure has all expected fields
204+
expect(lastRequest).to.have.property("functionName");
205+
expect(lastRequest).to.have.property("url");
206+
expect(lastRequest).to.have.property("params");
207+
208+
// URL should match configured server
209+
expect(lastRequest.url).to.include("test.count.ly");
210+
211+
// Params should have app_key
212+
expect(lastRequest.params).to.have.property("app_key", hp.appKey);
213+
});
214+
});
215+
});
216+
});

cypress/e2e/remaining_requests.cy.js

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,23 @@ describe("Remaining requests tests ", () => {
1616
it("Checks the requests for rr", () => {
1717
hp.haltAndClearStorage(() => {
1818
initMain(false);
19+
Countly.begin_session();
20+
Countly.end_session(undefined, true);
1921

20-
// We will expect 4 requests: health check, begin_session, end_session, orientation
21-
hp.interceptAndCheckRequests("POST", undefined, undefined, "?hc=*", "hc", (requestParams) => {
22-
const params = JSON.parse(requestParams.get("hc"));
23-
assert.isTrue(typeof params.el === "number");
24-
assert.isTrue(typeof params.wl === "number");
25-
assert.isTrue(typeof params.sc === "number");
26-
assert.isTrue(typeof params.em === "string");
27-
expect(requestParams.get("rr")).to.equal(null);
28-
});
2922
cy.wait(1000).then(() => {
30-
// Create a session
31-
Countly.begin_session();
32-
hp.interceptAndCheckRequests("POST", undefined, undefined, "?begin_session=*", "begin_session", (requestParams) => {
33-
expect(requestParams.get("begin_session")).to.equal("1");
34-
expect(requestParams.get("rr")).to.equal("3");
35-
expect(requestParams.get("av")).to.equal(av);
36-
});
37-
// End the session
38-
Countly.end_session(undefined, true);
39-
hp.interceptAndCheckRequests("POST", undefined, undefined, "?end_session=*", "end", (requestParams) => {
40-
expect(requestParams.get("end_session")).to.equal("1");
41-
expect(requestParams.get("rr")).to.equal("2");
42-
expect(requestParams.get("av")).to.equal(av);
43-
});
44-
hp.interceptAndCheckRequests("POST", undefined, undefined, undefined, "orientation", (requestParams) => {
45-
expect(JSON.parse(requestParams.get("events"))[0].key).to.equal("[CLY]_orientation");
46-
expect(requestParams.get("rr")).to.equal("1");
47-
expect(requestParams.get("av")).to.equal(av);
48-
});
49-
cy.wait(100).then(() => {
50-
cy.fetch_local_request_queue().then((rq) => {
51-
expect(rq.length).to.equal(0);
52-
});
53-
});
23+
var queues = Countly._internals.getLocalQueues();
24+
expect(queues.eventQ.length).to.equal(0);
25+
expect(queues.requestQ.length).to.equal(3);
26+
expect(queues.requestQ[0]["begin_session"]).to.equal(1);
27+
expect(queues.requestQ[1]["end_session"]).to.equal(1);
28+
expect(JSON.parse(queues.requestQ[2]["events"])[0].key).to.equal("[CLY]_orientation");
29+
30+
var requests = Countly._internals.testingGetRequests();
31+
expect(requests.length).to.equal(3);
32+
expect(requests[0].params["rr"]).to.equal(undefined);
33+
expect(requests[1].params["rr"]).to.equal(undefined);
34+
expect(requests[2].params["rr"]).to.equal(3);
35+
expect(requests[2].params["av"]).to.equal(av);
5436
});
5537
});
5638
});
@@ -62,9 +44,8 @@ describe("Remaining requests tests ", () => {
6244
Countly.begin_session();
6345
Countly.end_session(undefined, true);
6446
cy.fetch_local_request_queue().then((rq) => {
65-
// We expect 3 requests in queue: begin_session, end_session, orientation. health check was not in the queue
6647
expect(rq.length).to.equal(3);
67-
expect(rq[0].rr).to.equal(3);
48+
expect(rq[0].rr).to.equal(undefined);
6849
expect(rq[1].rr).to.equal(undefined);
6950
expect(rq[2].rr).to.equal(undefined);
7051

@@ -74,7 +55,7 @@ describe("Remaining requests tests ", () => {
7455
// We expect 4 requests in queue: begin_session, end_session, orientation and change ID
7556
cy.log(rq2);
7657
expect(rq2.length).to.equal(4);
77-
expect(rq2[0].rr).to.equal(3); // still 3 as it was assigned at the time of the first request creation
58+
expect(rq2[0].rr).to.equal(undefined);
7859
expect(rq2[1].rr).to.equal(undefined);
7960
expect(rq2[2].rr).to.equal(undefined);
8061
expect(rq2[3].rr).to.equal(undefined);

cypress/e2e/request_backoff.cy.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable require-jsdoc */
22
var Countly = require("../../lib/countly");
3-
var hp = require("../support/helper.js");
3+
var hp = require("../support/helper");
44

55
/**
66
1. check 30 sec timeout works(request are not removed): (2)
@@ -141,10 +141,10 @@ describe("Request Back-off Mechanism Tests", () => {
141141
cy.fetch_local_request_queue().then((rq) => {
142142
cy.log("Request Queue: " + JSON.stringify(rq));
143143
expect(rq.length).to.equal(0);
144+
cy.task("setResponseDelay", 0);
144145
Countly.add_event({ key: "test_2" });
145146
Countly.attempt_to_send_stored_requests();
146-
cy.task("setResponseDelay", 0);
147-
cy.wait(5000).then(() => {
147+
cy.wait(7000).then(() => {
148148
cy.fetch_local_request_queue().then((rq) => {
149149
cy.log("Request Queue: " + JSON.stringify(rq));
150150
expect(rq.length).to.equal(0);
@@ -165,13 +165,13 @@ describe("Request Back-off Mechanism Tests", () => {
165165
cy.fetch_local_request_queue().then((rq) => {
166166
cy.log("Request Queue: " + JSON.stringify(rq));
167167
expect(rq.length).to.equal(0);
168+
cy.task("setResponseDelay", 0);
168169
Countly.add_event({ key: "test_2" });
169170
Countly.attempt_to_send_stored_requests();
170-
cy.task("setResponseDelay", 0);
171171
cy.wait(8000).then(() => {
172-
cy.fetch_local_request_queue().then((rq2) => {
173-
cy.log("Request Queue: " + JSON.stringify(rq2));
174-
expect(rq2.length).to.equal(0);
172+
cy.fetch_local_request_queue().then((rq) => {
173+
cy.log("Request Queue: " + JSON.stringify(rq));
174+
expect(rq.length).to.equal(0);
175175
cy.task("stopServer");
176176
});
177177
});

cypress/e2e/sdk_info.cy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
var Countly = require("../../lib/countly");
44
var hp = require("../support/helper.js");
55
const SDK_NAME = "javascript_native_web";
6-
const SDK_VERSION = "25.4.5";
6+
const SDK_VERSION = "26.1.0";
77

88
function initMain(name, version) {
99
Countly.init({

0 commit comments

Comments
 (0)