Skip to content

Commit f64c3ba

Browse files
authored
[908] nps and survey manual reporting (#272)
* nps and survey manual reporting * removed double checks * added getFeedbackWidgetData * test name change * formated manual reporting * improved example * widgetresponse to result * changelog * wording changes
1 parent e7dd5c6 commit f64c3ba

File tree

4 files changed

+574
-22
lines changed

4 files changed

+574
-22
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 22.06.1
2+
- Added SDK calls to report Feedback widgets manually
3+
14
## 22.06.0
25
- Updated BoomerangJS to the latest version (1.737.0)
36
- Implemented static code analysis recommendations from Codacy, Snyk and Deep Scan
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
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+
const contactMe = true;
7+
const platform = "platform";
8+
const email = "email";
9+
const app_version = "app_version";
10+
const comment = "comment";
11+
const CountlyWidgetData = { true: true };
12+
13+
function CountlyFeedbackWidgetMaker(a, b) {
14+
return { _id: a, type: b };
15+
}
16+
17+
function widgetResponseMakerNpsRating(a) {
18+
return {
19+
contactMe: contactMe, // boolean
20+
rating: a, // number
21+
email: email,
22+
comment: comment // string
23+
};
24+
}
25+
function widgetResponseMakerSurvey(a, b, c, d) {
26+
return {
27+
a: b,
28+
c: d
29+
};
30+
}
31+
32+
function ratingMaker(a, b) {
33+
return {
34+
widget_id: a, // string
35+
contactMe: contactMe, // boolean
36+
platform: platform, // string
37+
app_version: app_version, // string
38+
rating: b, // number
39+
comment: comment, // string
40+
email: email // string
41+
};
42+
}
43+
// num is 1 for ratings, 2 for nps, 3 for surveys
44+
function common_rating_check(param, num) {
45+
// eslint-disable-next-line no-nested-ternary
46+
cy.expect(param[0].key).to.equal(num === 1 ? "[CLY]_star_rating" : num === 2 ? "[CLY]_nps" : "[CLY]_survey");
47+
cy.expect(param[0].segmentation.app_version).to.equal(app_version);
48+
cy.expect(param[0].segmentation.platform).to.equal(platform);
49+
if (num !== 3) {
50+
cy.expect(param[0].segmentation.comment).to.equal(comment);
51+
if (num === 1) {
52+
cy.expect(param[0].segmentation.contactMe).to.equal(contactMe);
53+
cy.expect(param[0].segmentation.email).to.equal(email);
54+
}
55+
}
56+
}
57+
58+
function initMain() {
59+
Countly.init({
60+
app_key: "YOUR_APP_KEY",
61+
url: "https://try.count.ly",
62+
max_events: -1,
63+
test_mode: true,
64+
debug: true
65+
66+
});
67+
}
68+
// TODO: Add more tests
69+
describe("Manual Rating Widget recording tests, old call ", () => {
70+
it("Checks if a rating object is send correctly", () => {
71+
hp.haltAndClearStorage(() => {
72+
initMain();
73+
Countly.recordRatingWidgetWithID(ratingMaker("123", 1));
74+
cy.fetch_local_event_queue().then((eq) => {
75+
cy.log(eq);
76+
expect(eq.length).to.equal(1);
77+
cy.check_commons(eq[0], 1);
78+
common_rating_check(eq, 1);
79+
cy.expect(eq[0].segmentation.rating).to.equal(1);
80+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
81+
});
82+
});
83+
});
84+
it("Checks if rating recording without id would be stopped", () => {
85+
hp.haltAndClearStorage(() => {
86+
initMain();
87+
Countly.recordRatingWidgetWithID(ratingMaker(undefined, 1));
88+
cy.fetch_local_event_queue().then((eq) => {
89+
cy.log(eq);
90+
expect(eq.length).to.equal(0);
91+
});
92+
});
93+
});
94+
it("Checks if rating recording without rating would be stopped", () => {
95+
hp.haltAndClearStorage(() => {
96+
initMain();
97+
Countly.recordRatingWidgetWithID(ratingMaker("123", undefined));
98+
cy.fetch_local_event_queue().then((eq) => {
99+
cy.log(eq);
100+
expect(eq.length).to.equal(0);
101+
});
102+
});
103+
});
104+
it("Checks if id and rating is enough", () => {
105+
hp.haltAndClearStorage(() => {
106+
initMain();
107+
Countly.recordRatingWidgetWithID({ widget_id: "123", rating: 1 });
108+
cy.fetch_local_event_queue().then((eq) => {
109+
cy.log(eq);
110+
expect(eq.length).to.equal(1);
111+
cy.check_commons(eq[0], 1);
112+
cy.expect(eq[0].segmentation.rating).to.equal(1);
113+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
114+
});
115+
});
116+
});
117+
it("Check improper rating number in fixed", () => {
118+
hp.haltAndClearStorage(() => {
119+
initMain();
120+
Countly.recordRatingWidgetWithID({ widget_id: "123", rating: 11 });
121+
cy.fetch_local_event_queue().then((eq) => {
122+
cy.log(eq);
123+
expect(eq.length).to.equal(1);
124+
cy.check_commons(eq[0], 1);
125+
cy.expect(eq[0].segmentation.rating).to.equal(5);
126+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
127+
});
128+
});
129+
});
130+
});
131+
describe("Manual nps recording tests ", () => {
132+
it("Checks if a nps is send correctly", () => {
133+
hp.haltAndClearStorage(() => {
134+
initMain();
135+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker("123", "nps"), CountlyWidgetData, widgetResponseMakerNpsRating(2));
136+
cy.fetch_local_event_queue().then((eq) => {
137+
cy.log(eq);
138+
expect(eq.length).to.equal(1);
139+
cy.check_commons(eq[0], 2);
140+
cy.expect(eq[0].segmentation.rating).to.equal(2);
141+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
142+
});
143+
});
144+
});
145+
it("Checks if nps would be omitted with no id", () => {
146+
hp.haltAndClearStorage(() => {
147+
initMain();
148+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker(undefined, "nps"), CountlyWidgetData, widgetResponseMakerNpsRating(2));
149+
cy.fetch_local_event_queue().then((eq) => {
150+
cy.log(eq);
151+
expect(eq.length).to.equal(0);
152+
});
153+
});
154+
});
155+
it("Checks if rating would be curbed", () => {
156+
hp.haltAndClearStorage(() => {
157+
initMain();
158+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker("123", "nps"), CountlyWidgetData, widgetResponseMakerNpsRating(11));
159+
cy.fetch_local_event_queue().then((eq) => {
160+
cy.log(eq);
161+
expect(eq.length).to.equal(1);
162+
cy.check_commons(eq[0], 2);
163+
cy.expect(eq[0].segmentation.rating).to.equal(10);
164+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
165+
});
166+
});
167+
});
168+
});
169+
describe("Manual survey recording tests ", () => {
170+
it("Checks if a survey is send correctly", () => {
171+
hp.haltAndClearStorage(() => {
172+
initMain();
173+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker("123", "survey"), CountlyWidgetData, widgetResponseMakerSurvey("a", "b", "c", 7));
174+
cy.fetch_local_event_queue().then((eq) => {
175+
cy.log(eq);
176+
expect(eq.length).to.equal(1);
177+
cy.check_commons(eq[0], 3);
178+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
179+
cy.expect(eq[0].segmentation.a).to.equal("b");
180+
cy.expect(eq[0].segmentation.c).to.equal(7);
181+
});
182+
});
183+
});
184+
it("Checks if null response would have closed flag", () => {
185+
hp.haltAndClearStorage(() => {
186+
initMain();
187+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker("123", "survey"), CountlyWidgetData, null);
188+
cy.fetch_local_event_queue().then((eq) => {
189+
cy.log(eq);
190+
expect(eq.length).to.equal(1);
191+
cy.check_commons(eq[0], 3);
192+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
193+
cy.expect(eq[0].segmentation.closed).to.equal(1);
194+
});
195+
});
196+
});
197+
it("Checks if no id would be rejected", () => {
198+
hp.haltAndClearStorage(() => {
199+
initMain();
200+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker(undefined, "survey"), CountlyWidgetData, widgetResponseMakerSurvey("a", "b", "c", 7));
201+
cy.fetch_local_event_queue().then((eq) => {
202+
cy.log(eq);
203+
expect(eq.length).to.equal(0);
204+
});
205+
});
206+
});
207+
});
208+
describe("Manual Rating widget recording tests, new call ", () => {
209+
it("Checks if a rating is send correctly", () => {
210+
hp.haltAndClearStorage(() => {
211+
initMain();
212+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker("123", "rating"), CountlyWidgetData, widgetResponseMakerNpsRating(3));
213+
cy.fetch_local_event_queue().then((eq) => {
214+
cy.log(eq);
215+
expect(eq.length).to.equal(1);
216+
cy.check_commons(eq[0], 1);
217+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
218+
cy.expect(eq[0].segmentation.rating).to.equal(3);
219+
});
220+
});
221+
});
222+
it("Checks if null response would have closed flag", () => {
223+
hp.haltAndClearStorage(() => {
224+
initMain();
225+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker("123", "rating"), CountlyWidgetData, null);
226+
cy.fetch_local_event_queue().then((eq) => {
227+
cy.log(eq);
228+
expect(eq.length).to.equal(1);
229+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
230+
cy.expect(eq[0].segmentation.closed).to.equal(1);
231+
});
232+
});
233+
});
234+
it("Checks if no id would be rejected", () => {
235+
hp.haltAndClearStorage(() => {
236+
initMain();
237+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker(undefined, "rating"), CountlyWidgetData, widgetResponseMakerNpsRating(3));
238+
cy.fetch_local_event_queue().then((eq) => {
239+
cy.log(eq);
240+
expect(eq.length).to.equal(0);
241+
});
242+
});
243+
});
244+
it("Checks if rating would be curbed", () => {
245+
hp.haltAndClearStorage(() => {
246+
initMain();
247+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidgetMaker("123", "rating"), CountlyWidgetData, widgetResponseMakerNpsRating(6));
248+
cy.fetch_local_event_queue().then((eq) => {
249+
cy.log(eq);
250+
expect(eq.length).to.equal(1);
251+
cy.check_commons(eq[0], 1);
252+
cy.expect(eq[0].segmentation.rating).to.equal(5);
253+
cy.expect(eq[0].segmentation.widget_id).to.equal("123");
254+
});
255+
});
256+
});
257+
});

examples/examples_feedback_widgets.html

+60-9
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,81 @@
99

1010
//initializing Countly with params and passing require_consent config as true as feedback widget depends on consent
1111
Countly.init({
12-
app_key: 'YOUR_APP_ID', //your app key
12+
app_key: 'YOUR_APP_KEY', //your app key
1313
url: 'https://try.count.ly', //your server goes here
1414
debug: true
1515
});
1616

17-
function enable() {
18-
//Fetch user's NPS and Survey feedbacks from the server
17+
function fetchAndDisplayWidget() {
18+
// Fetch user's NPS and Survey feedbacks from the server
1919
Countly.get_available_feedback_widgets(feedbackWidgetsCallback);
2020
}
21-
22-
//Surveys feedback callback function
21+
// Surveys feedback callback function
2322
function feedbackWidgetsCallback(countlyPresentableFeedback, err) {
2423
if (err) {
2524
console.log(err);
2625
return;
2726
}
28-
//The available feedback types are nps and survey, decide which one to show
27+
// Decide which which widget to show. Here first one is selected:
2928
var countlyFeedbackWidget = countlyPresentableFeedback[0];
3029

31-
//Define the element ID and the class name, optional
30+
// Define the element ID and the class name (optional)
3231
var selectorId = "";
3332
var selectorClass = "";
3433

35-
//Display the feedback widget to the end user
34+
// Display the feedback widget to the end user
3635
Countly.present_feedback_widget(countlyFeedbackWidget, selectorId, selectorClass);
3736
}
3837

38+
39+
var CountlyFeedbackWidget;
40+
var CountlyWidgetData;
41+
// an example of getting the widget list, using it to get widget data and then recording data for it manually. widgetType can be 'nps', 'survey' or 'rating'
42+
function getFeedbackWidgetListAndDoThings(widgetType) {
43+
// get the widget list
44+
Countly.get_available_feedback_widgets(
45+
// callback function, 1st param is the feedback widget list
46+
function (feedbackList, err) {
47+
if (err) {
48+
console.log(err);
49+
return;
50+
}
51+
var i = feedbackList.length - 1;
52+
while (i--) {
53+
if (feedbackList[i].type === widgetType) {
54+
CountlyFeedbackWidget = feedbackList[i];
55+
break;
56+
}
57+
}
58+
if (CountlyFeedbackWidget) {
59+
// Get data with the widget object
60+
Countly.getFeedbackWidgetData(CountlyFeedbackWidget,
61+
// callback function, 1st param is the feedback widget data
62+
function (feedbackData, err) {
63+
if (err) {
64+
console.log(err);
65+
return;
66+
}
67+
CountlyWidgetData = feedbackData;
68+
// record data according to the widget type
69+
if (CountlyWidgetData.type === 'nps') {
70+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidget, CountlyWidgetData, { rating: 3, comment: "comment" });
71+
} else if (CountlyWidgetData.type === 'survey') {
72+
var widgetResponse = {};
73+
// form the key/value pairs according to data
74+
widgetResponse["answ-" + CountlyWidgetData.questions[0].id] = CountlyWidgetData.questions[0].type === "rating" ? 3 : "answer";
75+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidget, CountlyWidgetData, widgetResponse);
76+
} else if (CountlyWidgetData.type === 'rating') {
77+
Countly.reportFeedbackWidgetManually(CountlyFeedbackWidget, CountlyWidgetData, { rating: 3, comment: "comment", email: "email", contactMe: true });
78+
}
79+
}
80+
81+
);
82+
} else {
83+
console.error("The widget type you are looking for does not exist")
84+
}
85+
})
86+
}
3987
</script>
4088
</head>
4189

@@ -49,7 +97,10 @@ <h1>Feedback Widgets</h1>
4997
<center>
5098
<img src="./images/team_countly.jpg" id="wallpaper" />
5199
<p><a href='http://count.ly/'>Count.ly</a></p>
52-
<p><button onclick="enable()">Enable Feedback Widget</button></p>
100+
<p><button onclick="fetchAndDisplayWidget()">Enable Feedback Widget</button></p>
101+
<p><button onclick="getFeedbackWidgetListAndDoThings('nps')">Manually Record NPS Data</button></p>
102+
<p><button onclick="getFeedbackWidgetListAndDoThings('survey')">Manually Record Survey Data</button></p>
103+
<p><button onclick="getFeedbackWidgetListAndDoThings('rating')">Manually Record Rating Data</button></p>
53104
</center>
54105
</body>
55106

0 commit comments

Comments
 (0)