I am working on Cypress API, trying to get a certain response but the problem is that I need to wait until I get a particular response, different from the previous one.
For example, repeating until "activated: true" and "fileType not inprogress".
This is the initial repsonse,
[
{
"filenameSource": "test",
"fileExt": "mp4",
"uniqueId": "18564Cm_BTo7Q0Sb0xCT",
"fileName": "test.mp4",
"title": "Test Video",
"language": "##",
"validFrom": "2022-10-01T00:00:00.000Z",
"rating": 0,
"aspect": "null",
"duration": -1,
"fps": 0,
"activated": false,
"fileSize": 0,
"importTime": "2022-11-07T12:14:31.813Z",
"fileType": "inprogress"
}
]
I think Request Polling is what you are trying to do
function req(attempts = 0) {
if (attempts === 100) {
throw new Error('Too many attempts')
}
cy.request('GET', ...)
.then(resp => resp.json())
.then(json => {
const data = resp.body
if (data[0].activated) {
return // break out of the recursive loop
}
cy.wait(200)
req(++attempts) // else recurse
})
}
cy.request('POST', ...) // initiate product
req() // wait for activated
cy.request('DELETE', ...) // now delete product
I have managed to resolve it with Cypress recurse function. Here is the link https://www.npmjs.com/package/cypress-recurse.
Thanks!
Related
I have a situation where I want to get the full (data) from the backend as a CSV file. I have already prepared the backend for that, but normally the front-end state => (filters) is not in contact with the backend unless I send a request, so I managed to solve the problem by mimicking the process of showing all data but by a custom button and a GET request ( not an ajax request ). knowing that I am using serverSide: true in datatables.
I prepared the backend to receive a request like ( Show All ) but I want that link to be sent by custom button ( Export All ) not by the show process itself as by the picture down because showing all data is not practical at all.
This is the code for the custom button
{
text: "Export All",
action: function (e, dt, node, config) {
// get the backend file here
},
},
So, How could I send a request like the same request sent by ( Show All ) by a custom button, I prepared the server to respond by the CSV file. but I need a way to get the same link to send a get request ( not by ajax ) by the same link that Show All sends?
If you are using serverSide: true that should mean you have too much data to use the default (serverSide: false) - because the browser/DataTables cannot handle the volume. For this reason I would say you should also not try to use the browser to generate a full export - it's going to be too much data (otherwise, why did you choose to use serverSide: true?).
Instead, use a server-side export utility - not DataTables.
But if you still want to pursuse this approach, you can build a custom button which downloads the entire data set to the DataTables (in your browser) and then exports that complete data to Excel.
Full Disclosure:
The following approach is inspired by the following DataTables forum post:
Customizing the data from export buttons
The following approach requires you to have a separate REST endpoint which delivers the entire data set as a JSON response (by contrast, the standard response should only be one page of data for the actual table data display and pagination.)
How you set up this endpoint is up to you (in Laravel, in your case).
Step 1: Create a custom button:
I tested with Excel, but you can do CSV, if you prefer.
buttons: [
{
extend: 'excelHtml5', // or 'csvHtml5'
text: 'All Data to Excel', // or CSV if you prefer
exportOptions: {
customizeData: function (d) {
var exportBody = getDataToExport();
d.body.length = 0;
d.body.push.apply(d.body, exportBody);
}
}
}
],
Step 2: The export function, used by the above button:
function GetDataToExport() {
var jsonResult = $.ajax({
url: '[your_GET_EVERYTHING_url_goes_here]',
success: function (result) {},
async: false
});
var exportBody = jsonResult.responseJSON.data;
return exportBody.map(function (el) {
return Object.keys(el).map(function (key) {
return el[key]
});
});
}
In the above code, my assumption is that the JSON response has the standard DataTables object structure - so, something like:
{
"data": [
{
"id": "1",
"name": "Tiger Nixon",
"position": "System Architect",
"salary": "$320,800",
"start_date": "2011/04/25",
"office": "Edinburgh",
"extn": "5421"
},
{
"id": "2",
"name": "Garrett Winters",
"position": "Accountant",
"salary": "$170,750",
"start_date": "2011/07/25",
"office": "Tokyo",
"extn": "8422"
},
{
"id": "3",
"name": "Ashton Cox",
"position": "Junior Technical Author",
"salary": "$86,000",
"start_date": "2009/01/12",
"office": "San Francisco",
"extn": "1562"
}
]
}
So, it's an object, containing a data array.
The DataTables customizeData function is what controls writing this complete JSON to the Excel file.
Overall, your DataTables code will look something like this:
$(document).ready(function() {
$('#example').DataTable( {
serverSide: true,
dom: 'Brftip',
buttons: [
{
extend: 'excelHtml5',
text: 'All Data to Excel',
exportOptions: {
customizeData: function (d) {
var exportBody = GetDataToExport();
d.body.length = 0;
d.body.push.apply(d.body, exportBody);
}
}
}
],
ajax: {
url: "[your_SINGLE_PAGE_url_goes_here]"
},
"columns": [
{ "title": "ID", "data": "id" },
{ "title": "Name", "data": "name" },
{ "title": "Position", "data": "position" },
{ "title": "Salary", "data": "salary" },
{ "title": "Start Date", "data": "start_date" },
{ "title": "Office", "data": "office" },
{ "title": "Extn.", "data": "extn" }
]
} );
} );
function GetDataToExport() {
var jsonResult = $.ajax({
url: '[your_GET_EVERYTHING_url_goes_here]',
success: function (result) {},
async: false
});
var exportBody = jsonResult.responseJSON.data;
return exportBody.map(function (el) {
return Object.keys(el).map(function (key) {
return el[key]
});
});
}
Just to repeat my initial warning: This is probably a bad idea, if you really needed to use serverSide: true because of the volume of data you have.
Use a server-side export tool instead - I'm sure Laravel/PHP has good support for generating Excel files.
Redux-Toolkit is not updating immidiately after dispatch.
I followed : https://redux-toolkit.js.org/tutorials/quick-start
My code:
quoteSlice.js
export const quotesSlice = createSlice({
name: 'quotes',
initialState,
reducers: {
setQuotes: (state, action) => {
console.log('before: ', current(state));
state.quotes = action.payload;
console.log('after: ', current(state));
},
},
});
slide.js
const swipeHandlerDelete = async key => {
console.log('swipeHandlerDelete:: ' + key);
// await deleteItem(database, key);
const filteredQuote = await quotes.filter(i => i.id !== key);
console.log('Before++');
console.log('filteredQuote.quote: ' + filteredQuote[0].quote);
console.log('quotes.quote: ' + quotes[0].quote);
await dispatch(setQuotes(filteredQuote));
console.log('After++');
console.log('quotes.quote: ' + quotes[0].quote);
};
Result: in Terminal
LOG swipeHandlerDelete:: 1
LOG Before++
LOG filteredQuote.quote: I'm well organized and highly productive
LOG quotes.quote: What is the most valuable use of my Time right now
LOG before: {"quotes": [{"created_at": "2022-07-22 10:10:10", "dd": "2022-07-02", "id": 1, "quote": "What is the most valuable use of my Time right now", "status": 1, "updated_at": ""}, {"created_at": "2022-07-22 10:10:10", "dd": "2022-07-02", "id": 2, "quote": "I'm well organized and highly productive", "status": 1, "updated_at": ""}, {"created_at": "2022-07-22 10:10:10", "dd": "2022-07-02", "id": 3, "quote": "Faith can move mountains", "status": 0, "updated_at": ""}]}
LOG after: {"quotes": [{"created_at": "2022-07-22 10:10:10", "dd": "2022-07-02", "id": 2, "quote": "I'm well organized and highly productive", "status": 1, "updated_at": ""}, {"created_at": "2022-07-22 10:10:10", "dd": "2022-07-02", "id": 3, "quote": "Faith can move mountains", "status": 0, "updated_at": ""}]}
LOG After++
LOG quotes.quote: What is the most valuable use of my Time right now
Here i'm deleting first one. i.e key=0, In this terminal result, before: and after: gets updated. But still its not changing in After++ . Why and how to do this? With this result I have to work further.
As for now what I have done is a SIMPLE THING
HINT:- In a single function(swipe/click/or any other mobile action) update redux dispatch for only one time.
Bad code:
if(a > b){
dispatch(setQuotes(a)); // First call
// do some process
var c = newFunction(x);
// do some process
dispatch(setQuotes(c)); // Second call
}
Good code:
const quotes = useSelector(state => state.quotes.quotes);
// ...
if(a > b){
var newQuote = quotes;
// do all process with newQuote
// finally
dispatch(setQuotes(newQuote)); // NOTE: Calling only once
}
You can do also this,
const quotes = useSelector(state => state.quotes.quotes);
// ...
if(a > b){
var newQuote = quotes;
// do all process with newQuote
try {
// some process
newQuote = [a,b,c];
dispatch(setValues(a)); // updating setValues only once
} catch (error) {
newQuote = [b,a,c];
dispatch(setValues(b)); // updating setValues only once
}
dispatch(setQuotes(newQuote)); // NOTE: Calling only once
}
When I use server side processing in datatable the sorting works but the sort icon does not change and stays in same direction. Below is the code snippet of my datatable configuration.
$('#dtSearchResult').DataTable({
"filter": false,
"pagingType": "simple_numbers",
"orderClasses": false,
"order": [[0, "asc"]],
"info": true,
"scrollY": "450px",
"scrollCollapse": true,
"bLengthChange": false,
"searching": true,
"bStateSave": false,
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": VMCreateExtraction.AppSecurity.websiteNode() + "/api/Collection/SearchCustIndividual",
"fnServerData": function (sSource, aoData, fnCallback) {
aoData.push({ "name": "ccUid", "value": ccUid });
//Below i am getting the echo that i will be sending to Server side
var echo = null;
for (var i = 0; i < aoData.length; i++) {
switch (aoData[i].name) {
case 'sEcho':
echo = aoData[i].value;
break;
default:
break;
}
}
$.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "GET",
"url": sSource,
"data": aoData,
success: function (msg, a, b) {
$.unblockUI();
var mappedCusNames = $.map(msg.Table, function (Item) {
return new searchGridListObj(Item);
});
var data = {
"draw": echo,
"recordsTotal": msg.Table2[0].TOTAL_NUMBER_OF_RECORDS,
"recordsFiltered": msg.Table1[0].FILTERED_RECORDS,
"data": mappedCusNames
};
fnCallback(data);
$("#dtSearchResult").show();
ko.cleanNode($('#dtSearchResult')[0]);
ko.applyBindings(VMCreateExtraction, $('#dtSearchResult')[0]);
}
})
},
"aoColumns": [{
"mDataProp": "C_UID"
}, {
"mDataProp": "C_LAST_NAME"
}, {
"mDataProp": "C_FIRST_NAME"
}, {
"mDataProp": "C_USER_ID"
}, {
"mDataProp": "C_EMAIL"
}, {
"mDataProp": "C_COMPANY"
}],
"aoColumnDefs": [{ "defaultContent": "", "targets": "_all" },
//I create a link in 1 st column
]
});
There is some configuration that I am missing here. I read on datatable forums and the only issue highlighted by people was that draw should be same as what we send on server side.
For anyone looking for an answer to this. Sad but i had to write my own function as below:
function sortIconHandler(thArray, sortCol, sortDir) {
for (i = 0; i < thArray.length; i++) {
if (thArray[i].classList.contains('sorting_asc')) {
thArray[i].classList.remove('sorting_asc');
thArray[i].classList.add("sorting");
}
else if (thArray[i].classList.contains('sorting_desc')) {
thArray[i].classList.remove('sorting_desc');
thArray[i].classList.add("sorting");
}
if (i == sortCol) {
if (sortDir == 'asc') {
thArray[i].classList.remove('sorting');
thArray[i].classList.add("sorting_asc");
}
else {
thArray[i].classList.remove('sorting');
thArray[i].classList.add("sorting_desc");
}
}
}
}
tharrray-> The array of all row headers(You can just write a jquery selector for this).
sortCol->Column on which sort is clicked (Datatable param iSortCol_0)
sortDir -> Sorting direction (Datatable param sSortDir_0)
I know this is an old thread, but make sure you don't have an .off() somewhere associated with the tables capture group in jQuery. I had a click event that (for some reason) I attached an off function to.. Took me 3 days to find it.
I'm trying to read emails responded by the Gmail API.
I have trouble accessing all the "parts". And don't have great ways to traverse through the response. I'm also lost as to how many parts can exist so that I can make sure I read the different email responses properly. I've shortened the response below...
{ "payload": { "mimeType": "multipart/mixed", "filename": "",
], "body": { "size": 0 }, "parts": [ {
"body": {
"size": 0
},
"parts": [
{
"partId": "0.0",
"mimeType": "text/plain",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/plain; charset=\"us-ascii\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 2317,
"data": "RGVhciBNSVQgQ2x1YiBWb2x1bnRlZXJzIGluIEFzaWEsDQoNCkJ5IG5vdyBlYWNoIG9mIHlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBpbnZpdGF0aW9ucyB0byB0aGUgcmVjZXB0aW9ucyBpbiBib3RoIFNpbmdhcG9yZSBhbmQgSG9uZyBLb25nIHdpdGggUHJlc2lkZW50IFJlaWYgb24gTm92ZW1iZXIgNyBhbmQgTm92ZW1iZXIg"
}
},
{
"partId": "0.1",
"mimeType": "text/html",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/html; charset=\"us-ascii\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 9116,
"data": "PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2UvMjA"
}
}
] }, {
"partId": "1",
"mimeType": "text/plain",
"filename": "",
"body": {
"size": 411,
"data": "X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NClRoYW5rIHlvdSBmb3IgYWxsb3dpbmcgdXMgdG8gcmVhY2ggeW91IGJ5IGVtYWlsLCB0aGUgbW9zdCBpbW1lZGlhdGUgbWVhbnMgZm9yIHNoYXJpbmcgaW5mb3JtYXRpb24gd2l0aCBNSVQgYWx1bW5pLiANCklmIHlvdSB3b3VsZCBsaWtlIHRvIHVuc3Vic2NyaWJlIGZyb20gdGhpcyBtYWlsaW5nIGxpc3Qgc2VuZCBhIGJsYW5rIGVtYWlsIHRvIGxpc3RfdW5zdWJzY3JpYmVAYWx1bS5taXQuZWR1IGFuZCBwdXQgdGhlIGxpc3QgbmFtZSBpbiB0aGUgc3ViamVjdCBsaW5lLg0KRm9yIGV4YW1wbGU6DQpUbzogbGlzdF91bnN1YnNjcmliZUBhbHVtLm1pdC5lZHUNCkNjOg0KU3ViamVjdDogYXNpYW9mZg0K"
} } ] } }
Is there something I'm missing?
A MIME message is not just an array it's a full blown tree structure. So you'll have to traverse it to correctly handle it. Luckily JSON parsers are plentiful and the problem can easily be handled with recursion. In many languages there exist very useful email parsing libraries that can make accessing traditional parts (e.g. the text/plain or text/html displayable part, or attachments) not too laborious.
You'll have to set up walker functions to traverse through the json and pick out the bits you are after. Here is a part of what I wrote. This may help you jumpstart your code. NOTE: this is used inside of wordpress...hence the special jQuery call. Not needed if you do not need to use jquery inside wordpress.
function makeApiCall() {
gapi.client.load('gmail', 'v1', function() {
//console.log('inside call: '+myquery);
var request = gapi.client.gmail.users.messages.list({
'userId': 'me',
'q': myquery
});
request.execute(function(resp) {
jQuery(document).ready(function($) {
//console.log(resp);
//$('.ASAP-emailhouse').height(300);
$.each(resp.messages, function(index, value){
messageId = value.id;
var messagerequest = gapi.client.gmail.users.messages.get({
'userId': 'me',
'id': messageId
});//end var message request
messagerequest.execute(function(messageresp) {
//console.log(messageresp);
$.each(messageresp, responsewalker);
function responsewalker(key, response){
messagedeets={};
$.each(messageresp.payload.headers, headerwalker);
function headerwalker(headerkey, header){
if(header.name =='Date'){
d = new Date(header.value);
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1; //Months are zero based
var curr_year = d.getFullYear();
var formatteddate = curr_month+'/'+curr_date+'/'+curr_year;
messagedeets['date']=formatteddate;
//$('.ASAP-emailhouse').append('<p>'+header.value+'</p>');
}
if(header.name =='Subject'){
//console.log(header.value);
messagedeets.subject=header.value;
}
}
messagedeets.body = {};
$.each(messageresp.payload.parts, walker);
function walker(partskey, value) {
//console.log(value.body);
if (value.body.data !== "undefined") {
//console.log(value.body);
var messagebody = atob(value.body.data);
messagedeets.body.partskey = messagebody;
}
console.log(messagedeets);
$('.ASAP-emailhouse').append('<div class="messagedeets"><p class="message-date">'+messagedeets.date+': <span class="message-subject">'+messagedeets.subject+'</span></p><p>'+messagedeets.body.partskey+'</p></div>');
}//end responsewalker
//$('.ASAP-emailhouse').append('</li>');
}
//$('.ASAP-emailhouse').append('</ul>');
});//end message request
});//end each message id
});//end jquery wrapper for wordpress
});//end request execute list messages
});//end gapi client load gmail
}
The MIME parts you are looking for are in an array. JSON does not tell you up front how many items are in an array. Even MIME itself does not provide a way of knowing how many parts are present without looking at the entire message. You will just have to traverse the entire array to know how many parts are in it, and process each part as you encounter it.
To know how much parts exists, you can just use the Length property.
Example :
json.payload.parts.length
For your example, this property is 2 because there are 2 parts.
My system running at least two years. Most push notification requests got 200. But, recently, I found I got 500 frequently.
Nealy 10% push notifications got 500.
Please HELP!!!
I have resend the problem messages, every thing is fine.
Example:
Request is:
{
"request": {
"application": "3DXXX-59XXX",
"username": "MyXXXXX",
"password": "********",
"notifications": [
{
"send_date": "now",
"content": {
"en": "Subscriber ID. 9000 Close User 01"
},
"link": "",
"data": {
"userID": "12345"
},
"wp_type": "",
"wp_background": "",
"wp_count": "",
"ios_badges": 51,
"ios_sound": "short-tone.caf",
"devices": [
"APA91bHZHEhIMjVYwxyMk-4-YObazHfcxlQq7CmYto930nuIqHlQGCdzUQsnDcnHTB78wUcTlm-qhV3ipMqe9HO3kTqD9j_zgzSUUAdoGK0fbeRRGMNn69Z63BlQ9RqIdioZ4J2NFA0DLOUkroImk-it8p_3Glr5bRlnrl1_wT3ycXfsgvQZq4g"
],
"page_id": "0",
"android_sound": "five_sectoneone"
}
]
}
}
Response is:
{"status_code":500,"status_message":"Invalid devices list"}
==============================================================
========================= Update =============================
After I upgrade Pushwoosh API from V1.2 to V1.3, the problem is gone.
However, new problem comes.
My sample is:
request :
{
"request": {
"application": "3DXXX-59XXX",
"auth": "*********WqLiS5ZM2****************************************9eib******",
"notifications": [
{
"send_date": "now",
"content": {
"en": "Jones Residence Tue,17Jul 12:12 Test from Robbie......."
},
"link": "",
"data": {
"userID": "12345"
},
"wp_type": "",
"wp_background": "",
"wp_count": "",
"ios_badges": 39,
"ios_sound": "short-tone.caf",
"devices": [
"298eeXXXXa26849cc77da16adXXXXc1c801df12e79bad1e724829aXXXXcbe07d" //I hashed real ID here
],
"page_id": "0",
"android_sound": "five_sectoneone"
}
]
}
}
Response is:
{
"status_code": 200,
"status_message": "OK",
"response": {
"Messages": [
"D954-3C45B1AA-AA6293E5"
],
"UnknownDevices": {
"D954-3C45B1AA-AA6293E5": [
"298eeXXXXa26849cc77da16adXXXXc1c801df12e79bad1e724829aXXXXcbe07d" //I hashed real ID here
]
}
}
}
I see you already wrote the question in Pushwoosh community. I'll post the answer here as well.
The "UnknownDevice" warning indicates that the push token that you have put in the "devices" section of the createMessage request isn't in our databases.
There are several reasons for that:
1) The application was deleted from the device.
2) The push token was renewed. APNs/GCM/etc. tends to change push tokens from time to time, and we remove outdated push tokens from our servers. (This happens VERY rarely)
3) There is a misprint in your request. (I'm sure this is not the case)
Please note that in order to keep your userbase up-to-date you can use getUnregisteredDevices method, which would return a last thousand of removed push tokens. You will need to call this on a regular basis.
P.S. https://community.pushwoosh.com/questions/998/pushwoosh-create-message-get-200-but-says-unknowndevices
P.P.S. Do not use 1.2 API, it is very old and will be deprecated soon.
I think, you use wrong device token. Don't use device UUID. You can send device token to your database after put it deviceArray in the Java code.
Edit PushwooshiOS.js file;
pushNotification.registerDevice(
function(status)
{
var deviceToken = status['deviceToken'];
console.warn('registerDevice: ' + deviceToken);
$.ajax({
url : "http://ip:port/deviceid/"+deviceToken,
dataType : "json",
success : function(a, b, c) {
console.log("send tokens to server after call t in your json array");
},
error : function(a, b, c) {
console.log("err a ", a);
console.log("err b ", b);
console.log("err c ", c);
console.log("err c ", c);
}
});
onPushwooshiOSInitialized(deviceToken);
},
function(status)
{
console.warn('failed to register : ' + JSON.stringify(status));
//alert(JSON.stringify(['failed to register ', status]));
}
);
Java code
String method = "createMessage";
URL url = new URL(PUSHWOOSH_SERVICE_BASE_URL + method);
JSONArray deviceArray = new JSONArray();
// put your device tokens
deviceArray.put(deviceToken);
JSONArray notificationsArray = new JSONArray()
.put(new JSONObject().put("send_date", "now")
.put("content", "A test push")
.put("devices",deviceArray));
JSONObject requestObject = new JSONObject()
.put("application", APPLICATION_CODE)
.put("auth", AUTH_TOKEN)
.put("notifications", notificationsArray);
JSONObject mainRequest = new JSONObject().put("request", requestObject);
JSONObject response = SendServerRequest.sendJSONRequest(url, mainRequest.toString());