Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Staging 24.11 #18

Merged
merged 32 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ccf2bfe
Added a way to explicity process the async queue
turtledreams Jan 19, 2024
dc07a42
feat: warn for defaults
arifBurakDemiray Jan 25, 2024
8e1d48c
feat: update warns
arifBurakDemiray Jan 26, 2024
e58624a
seperated functions
turtledreams Jan 29, 2024
d3e1eca
removed unnecessary test
turtledreams Jan 29, 2024
e3392d3
Regex comments
turtledreams Jan 29, 2024
4fcdb8f
Merge pull request #10 from Countly/regex
ArtursKadikis Jan 29, 2024
8fa0988
Merge pull request #7 from Countly/asyncqueue-processing
ArtursKadikis Jan 29, 2024
d882f8b
Merge pull request #8 from Countly/warn_def
ArtursKadikis Jan 29, 2024
86b3734
Update README.md
arifBurakDemiray Feb 12, 2024
c5a94df
Merge pull request #11 from Countly/arifBurakDemiray-patch-1
ArtursKadikis Feb 12, 2024
3e921b8
[fix] track errors
turtledreams Mar 26, 2024
f7571d3
Merge pull request #12 from Countly/tracking-errors
ArtursKadikis Mar 26, 2024
3a68d7d
supportr
turtledreams Apr 4, 2024
f238494
rem
turtledreams Apr 4, 2024
bd53fa0
c
turtledreams Apr 8, 2024
1c6b61b
cc
turtledreams Apr 8, 2024
ba4e2c3
empty string issue
turtledreams Apr 9, 2024
e1232c3
Added salt
turtledreams Apr 23, 2024
00c5950
worker
turtledreams Apr 23, 2024
39b0fd8
moved
turtledreams Apr 23, 2024
27f1d29
version update
turtledreams Apr 23, 2024
fe04aef
changelog
turtledreams Apr 23, 2024
b464d35
Merge pull request #13 from Countly/widget-support
turtledreams Jun 11, 2024
040d8d2
Merge pull request #14 from Countly/hc-empty-string-issue
turtledreams Jun 11, 2024
0379319
Merge branch 'staging' into salt-checksum
turtledreams Jun 11, 2024
271f385
Merge pull request #15 from Countly/salt-checksum
turtledreams Jun 11, 2024
f19851e
set id addition
turtledreams Jun 12, 2024
cf5c572
Merge pull request #16 from Countly/set_id-addition
turtledreams Jun 12, 2024
7aaf344
initial changes
turtledreams Oct 19, 2024
450c9fe
more fixes
turtledreams Nov 12, 2024
5dfe7c7
Merge pull request #17 from Countly/4.2-fixes
turtledreams Nov 12, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/
dist/
rollup.config.js
Countly.d.ts
```
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
## 24.11.0

* Mitigated an issue where SDK could try to send old stored offline mode data during init if `clear_stored_id` was true
* Mitigated an issue where the SDK could stayed on offline mode after the first init with `offline_mode` set to true
* Mitigated an issue where old Rating widget stickers were not cleared when a new one was presented

* Improved view tracking logic
* Default request method is now set to "POST"
* Healtchecks won't be sent in offline mode anymore
* Added a new interface 'feedback' which includes convenience methods to show feedback widgets:
* showNPS([String nameIDorTag]) - for displaying the first available NPS widget or one with the given name, Tag or ID value
* showSurvey([String nameIDorTag]) - for displaying the first available Survey widget or one with the given name, Tag or ID value
* showRating([String nameIDorTag]) - for displaying the first available Rating widget or one with the given name, Tag or ID value

## 24.4.1

* Added a new method `set_id(newDeviceId)` for managing device id changes according to the device ID Type.

## 24.4.0

! Minor breaking change ! For implementations using `salt` the browser compatibility is tied to SubtleCrypto's `digest` method support

* Added the `salt` init config flag to add checksums to requests (for secure contexts only)
* Added support for Feedback Widgets' 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
289 changes: 289 additions & 0 deletions cypress/e2e/async_queue.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
/* eslint-disable require-jsdoc */
var Countly = require("../../Countly.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) => {
// Check that nothing sent to request queue
expect(rq.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) => {
// Check that event queue is empty
expect(eq.length).to.equal(0);
cy.fetch_local_request_queue().then((rq) => {
// Check that events are now in request queue
expect(rq.length).to.equal(1);
const eventsArray = JSON.parse(rq[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) => {
// Check that events are now in request queue (second request is begin session for new device ID)
expect(rq.length).to.equal(2);
const eventsArray = JSON.parse(rq[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[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) => {
// Check that events are now in request queue (second request is user details)
expect(rq.length).to.equal(2);
const eventsArray = JSON.parse(rq[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[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) => {
// Check that events are now in request queue (second request is user details)
expect(rq.length).to.equal(2);
const eventsArray = JSON.parse(rq[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[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) => {
// Check that event queue is empty as all must be in request queue
expect(eq.length).to.equal(0);
cy.fetch_local_request_queue().then((rq) => {
// Check that events are now in request queue
expect(rq.length).to.equal(1);
const eventsArray = JSON.parse(rq[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");
});
});
});
});
});
});
});
});
Loading