Skip to content

Commit

Permalink
Merge pull request #490 from Countly/staging
Browse files Browse the repository at this point in the history
24.4.0 Release
  • Loading branch information
turtledreams authored Apr 24, 2024
2 parents 8c4b464 + d428110 commit fb102da
Show file tree
Hide file tree
Showing 35 changed files with 1,022 additions and 332 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -54,7 +54,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -68,4 +68,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## 24.4.0
! Minor breaking change ! For implementations using `salt` the browser compatability is tied to SubtleCrypto's `digest` method support

- Added the `salt` init config flag to add checksums to requests (for secure contexts only)
- Improved Health Check feature stability
- Added support for Feedback Widget terms and conditions

## 23.12.6
- Mitigated an issue where error tracking could prevent SDK initialization in async mode

## 23.12.5
- Mitigated an issue where the SDK was not emptying the async queue explicity when closing a browser

## 23.12.4
- Enhanced userAgentData detection for bot filtering

Expand Down
290 changes: 290 additions & 0 deletions cypress/integration/async_queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
/* eslint-disable cypress/no-unnecessary-waiting */
/* eslint-disable require-jsdoc */
var Countly = require("../../lib/countly");
// import * as Countly from "../../dist/countly_umd.js";
var hp = require("../support/helper.js");

function initMain(clear) {
Countly.init({
app_key: "YOUR_APP_KEY",
url: "https://your.domain.count.ly",
debug: true,
test_mode: true,
clear_stored_id: clear
});
}

function event(number) {
return {
key: `event_${number}`,
segmentation: {
id: number
}
};
}

// All the tests below checks if the functions are working correctly
// Currently tests for 'beforeunload' and 'unload' events has to be done manually by using the throttling option of the browser
describe("Test Countly.q related methods and processes", () => {
// For this tests we disable the internal heatbeat and use processAsyncQueue and sendEventsForced
// So we are able to test if those functions work as intented:
// processAsyncQueue should send events from .q to event queue
// sendEventsForced should send events from event queue to request queue (it also calls processAsyncQueue)
it("Check processAsyncQueue and sendEventsForced works as expected", () => {
hp.haltAndClearStorage(() => {
// Disable heartbeat and init the SDK
Countly.noHeartBeat = true;
initMain();
cy.wait(1000);

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);

// Add 4 events to the .q
Countly.q.push(["track_errors"]); // adding this as calling it during init used to cause an error (at v23.12.5)
Countly.q.push(["add_event", event(1)]);
Countly.q.push(["add_event", event(2)]);
Countly.q.push(["add_event", event(3)]);
Countly.q.push(["add_event", event(4)]);
// Check that the .q has 4 events
expect(Countly.q.length).to.equal(5);

cy.fetch_local_event_queue().then((rq) => {
// Check that events are still in .q
expect(Countly.q.length).to.equal(5);

// Check that the event queue is empty
expect(rq.length).to.equal(0);

// Process the .q (should send things to the event queue)
Countly._internals.processAsyncQueue();

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);

cy.fetch_local_request_queue().then((rq_2) => {
// Check that nothing sent to request queue
expect(rq_2.length).to.equal(0);
cy.fetch_local_event_queue().then((eq) => {
// Check that events are now in event queue
expect(eq.length).to.equal(4);

// Send events from event queue to request queue
Countly._internals.sendEventsForced();
cy.fetch_local_event_queue().then((eq_2) => {
// Check that event queue is empty
expect(eq_2.length).to.equal(0);
cy.fetch_local_request_queue().then((rq_3) => {
// Check that events are now in request queue
expect(rq_3.length).to.equal(1);
const eventsArray = JSON.parse(rq_3[0].events);
expect(eventsArray[0].key).to.equal("event_1");
expect(eventsArray[1].key).to.equal("event_2");
expect(eventsArray[2].key).to.equal("event_3");
expect(eventsArray[3].key).to.equal("event_4");
});
});
});
});
});
});
});
// This test is same with the ones above but this time we use change_id to trigger processAsyncQueue
it("Check changing device ID without merge empties the .q", () => {
hp.haltAndClearStorage(() => {
// Disable heartbeat and init the SDK
Countly.noHeartBeat = true;
Countly.q = [];
initMain();
cy.wait(1000);

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);

// Add 4 events to the .q
Countly.q.push(["add_event", event(1)]);
Countly.q.push(["add_event", event(2)]);
Countly.q.push(["add_event", event(3)]);
Countly.q.push(["add_event", event(4)]);
// Check that the .q has 4 events
expect(Countly.q.length).to.equal(4);

cy.fetch_local_event_queue().then((rq) => {
// Check that the event queue is empty
expect(rq.length).to.equal(0);

// Check that events are still in .q
expect(Countly.q.length).to.equal(4);

// Trigger processAsyncQueue by changing device ID without merge
Countly.change_id("new_user_id", false);

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);
cy.fetch_local_event_queue().then((eq) => {
// Check that event queue has new device ID's orientation event
expect(eq.length).to.equal(1);
expect(eq[0].key).to.equal("[CLY]_orientation");
cy.fetch_local_request_queue().then((rq_2) => {
// Check that events are now in request queue (second request is begin session for new device ID)
expect(rq_2.length).to.equal(2);
const eventsArray = JSON.parse(rq_2[0].events);
expect(eventsArray[0].key).to.equal("event_1");
expect(eventsArray[1].key).to.equal("event_2");
expect(eventsArray[2].key).to.equal("event_3");
expect(eventsArray[3].key).to.equal("event_4");
// check begin session
expect(rq_2[1].begin_session).to.equal(1);
});
});
});
});
});
// This test checks if calling user_details triggers processAsyncQueue (it sends events from .q to event queue and then to request queue)
it("Check sending user details empties .q", () => {
hp.haltAndClearStorage(() => {
// Disable heartbeat and init the SDK
Countly.noHeartBeat = true;
Countly.q = [];
initMain();
cy.wait(1000);

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);

// Add 4 events to the .q
Countly.q.push(["add_event", event(1)]);
Countly.q.push(["add_event", event(2)]);
Countly.q.push(["add_event", event(3)]);
Countly.q.push(["add_event", event(4)]);
// Check that the .q has 4 events
expect(Countly.q.length).to.equal(4);

cy.fetch_local_event_queue().then((rq) => {
// Check that the event queue is empty
expect(rq.length).to.equal(0);

// Check that events are still in .q
expect(Countly.q.length).to.equal(4);

// Trigger processAsyncQueue by adding user details
Countly.user_details({ name: "test_user" });

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);
cy.fetch_local_event_queue().then((eq) => {
// Check that event queue is empty
expect(eq.length).to.equal(0);
cy.fetch_local_request_queue().then((rq_2) => {
// Check that events are now in request queue (second request is user details)
expect(rq_2.length).to.equal(2);
const eventsArray = JSON.parse(rq_2[0].events);
expect(eventsArray[0].key).to.equal("event_1");
expect(eventsArray[1].key).to.equal("event_2");
expect(eventsArray[2].key).to.equal("event_3");
expect(eventsArray[3].key).to.equal("event_4");
// check user details
const user_details = JSON.parse(rq_2[1].user_details);
expect(user_details.name).to.equal("test_user");
});
});
});
});
});
// This Test checks if calling userData.save triggers processAsyncQueue (it sends events from .q to event queue and then to request queue)
it("Check sending custom user info empties .q", () => {
hp.haltAndClearStorage(() => {
// Disable heartbeat and init the SDK
Countly.noHeartBeat = true;
Countly.q = [];
initMain();
cy.wait(1000);

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);

// Add 4 events to the .q
Countly.q.push(["add_event", event(1)]);
Countly.q.push(["add_event", event(2)]);
Countly.q.push(["add_event", event(3)]);
Countly.q.push(["add_event", event(4)]);
// Check that the .q has 4 events
expect(Countly.q.length).to.equal(4);

cy.fetch_local_event_queue().then((rq) => {
// Check that the event queue is empty
expect(rq.length).to.equal(0);

// Check that events are still in .q
expect(Countly.q.length).to.equal(4);

// Trigger processAsyncQueue by saving UserData
Countly.userData.set("name", "test_user");
Countly.userData.save();

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);
cy.fetch_local_event_queue().then((eq) => {
// Check that event queue is empty
expect(eq.length).to.equal(0);
cy.fetch_local_request_queue().then((rq_2) => {
// Check that events are now in request queue (second request is user details)
expect(rq_2.length).to.equal(2);
const eventsArray = JSON.parse(rq_2[0].events);
expect(eventsArray[0].key).to.equal("event_1");
expect(eventsArray[1].key).to.equal("event_2");
expect(eventsArray[2].key).to.equal("event_3");
expect(eventsArray[3].key).to.equal("event_4");
// check user data
const user_details = JSON.parse(rq_2[1].user_details);
expect(user_details.custom.name).to.equal("test_user");
});
});
});
});
});
// This test check if the heartbeat is processing the .q (executes processAsyncQueue)
it("Check if heatbeat is processing .q", () => {
hp.haltAndClearStorage(() => {
// init the SDK
Countly.q = [];
initMain();

// Check that the .q is empty
expect(Countly.q.length).to.equal(0);
cy.fetch_local_event_queue().then((eq) => {
// Check that the event queue is empty
expect(eq.length).to.equal(0);
cy.fetch_local_request_queue().then((rq) => {
// Check that the request queue is empty
expect(rq.length).to.equal(0);
// Add 4 events to the .q
Countly.q.push(["add_event", event(1)]);
Countly.q.push(["add_event", event(2)]);
Countly.q.push(["add_event", event(3)]);
Countly.q.push(["add_event", event(4)]);
// Check that the .q has 4 events
expect(Countly.q.length).to.equal(4);
// Wait for heartBeat to process the .q
cy.wait(1500).then(() => {
// Check that the .q is empty
expect(Countly.q.length).to.equal(0);
cy.fetch_local_event_queue().then((eq_2) => {
// Check that event queue is empty as all must be in request queue
expect(eq_2.length).to.equal(0);
cy.fetch_local_request_queue().then((rq_2) => {
// Check that events are now in request queue
expect(rq_2.length).to.equal(1);
const eventsArray = JSON.parse(rq_2[0].events);
expect(eventsArray[0].key).to.equal("event_1");
expect(eventsArray[1].key).to.equal("event_2");
expect(eventsArray[2].key).to.equal("event_3");
expect(eventsArray[3].key).to.equal("event_4");
});
});
});
});
});
});
});
});
2 changes: 1 addition & 1 deletion cypress/integration/bridge_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function initMain(name, version) {
}

const SDK_NAME = "javascript_native_web";
const SDK_VERSION = "23.12.4";
const SDK_VERSION = "24.4.0";

// tests
describe("Bridged SDK Utilities Tests", () => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/health_check.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("Health Check tests ", () => {
// Test the 'hc' parameter
const hcParam = url.searchParams.get("hc");
const hcParamObj = JSON.parse(hcParam);
expect(hcParamObj).to.eql({ el: 0, wl: 0, sc: -1, em: "\"\"" });
expect(hcParamObj).to.eql({ el: 0, wl: 0, sc: -1, em: "" });

// Test the 'metrics' parameter
const metricsParam = url.searchParams.get("metrics");
Expand Down
Loading

0 comments on commit fb102da

Please sign in to comment.