Inertiajs - Asynch Redirect - laravel

I have a short question.
Does inertia render asynch?
I realized, as soon I delete a DB - Entry, while I connect to new Nav-Link direct afterwards (Inertia.onStart)- which redirects me on another Page, the changes (onSuccess) wont be showed up.
Inertia.post('data-delete', {
id: this.meeeh.data[index].id,
}, {
preserveScroll: true,
onBefore: () => {
window.Toast.confirm('Delete?');
},
onStart: (visit) => {
window.Toast.load('Delete...');
},
onSuccess: (page) => {
return Promise.all([
window.Toast.success(page.props.toast),
/** Wont show after click another Link in Navbar */
])
},
onError: (errors) => {
window.Toast.error(errors);
}
});
How does it come, I have to wait until the process is Finished - otherwise my Page is not working correctly?

Not sure if I understand what you're looking for.
onSuccess runs immediately after the post request has finished AND in successful. It is completely separated from other links and it's purpose (if your returning a Promise from it) is to delay the execution of the onFinish handler.
From the docs:
It's also possible to return a promise from the onSuccess() and
onError() callbacks. This will delay the "finish" event until the
promise has resolved.
I also believe there's some problem in your code: Promise.all should receive an array os Promises and I'm pretty sure window.Toast.success(page.props.toast) isn't returning one, is it?
So... chances are that your Promise.all is never resolving.

Related

How to get cypress to block datadog requests

We recently installed datadogRUM in our application and now so many DD events kick off in my cypress test that they cause a timeout and failure
I have tried cy.intercept in multiple ways:
cy.intercept('POST', 'https://rum.browser-intake-datadoghq.com/*', {
statusCode: 202,
body: {
},
}).as('datadogRUM');
cy.intercept('POST', 'https://rum-http-intake.logs.datadoghq.com/*', {});
cy.intercept(/\.*datadog.*$/, (req) => {
console.log('DATADOG INTERCEPTED');
req.reply("console.log('datadog intercept');");
});
cy.intercept({
method: 'POST',
url: '/\.*datadog.*$/'
}, req => {
req.destroy();
});
cy.intercept('POST', 'https://rum-http-intake.logs.datadoghq.com/*', { forceNetworkError: true });
just to start. I feel like I've tried every possible variation. I also created a cypress.json file in my /cypress folder
{
"blockHosts": "*datadoghq.com/*"
}
I get hundreds of calls back in my network tab to https://rum.browser-intake-datadoghq.com/api/v2/rum with the preview of console.log('datadog intercept') as I've intercepted them. They all display the solid blue line as if they are being intercepted and blocked. When I set the intercept to an alias I see the alias in my cypress runner window. But there are no 503s or 404s anywhere. The page still fills up with events, cypress gets overloaded, and my test times out.
I even tried copying the data-dog-rum.ts from the src/utils folder to cypress/utils and either commenting out everything or setting the sampleRate to 0, no dice.
EDIT: I am able to get the test passing by adding
Cypress.on('uncaught:exception', () => {
// returning false here prevents Cypress from
// failing the test
return false;
});
to my support/index.js but now whether I add a cy.intercept in my test makes absolutely no difference. The page still fills up with datadog requests regardless, and whether they come back as 200/pending/cancelled, they still delay a single it block in a spec to where it takes 60 seconds to run instead of approx 10 seconds
You can use javascript to perform the stub inside the routeHandler
cy.intercept('*', (req) => { // look at everything
if (req.url.includes('datadoghq')) { // add more conditions if needed
req.reply({}) // prevent request reaching the server
}
})
blockhosts should work with
Pass only the host
{
"blockHosts": "*datadoghq.com"
}

How do you wait on multiple XHR in Cypress that match the same intercept

In my app after login in from a clean state, there are a series of sync queries that are being fired to make sure that the local data is updated. There is a loading screen while this is happening. I just need to cypress to wait for all these calls to finish before performing the test.
cy.intercept() is identifying the call, but cy.wait() only waits for the first one to be finished.
Is there a way to create the alias dynamilcally or have the application wait for the spinner to disapper?
describe('Navigation', function () {
beforeEach(function () {
// Programmatically login via Amazon Cognito API
cy.intercept('POST', '**/graphql').as('dataStore');
cy.loginByCognitoApi(Cypress.env('cognito_username'), Cypress.env('cognito_password'));
cy.wait(['#dataStore']);
});
it('shows logged in', function () {
cy.get('[data-test=logo]').should('be.visible');
});
You can repeat wait on a single intercept, so count up the number of orange dataStore tags (looks like 11) and wait that amount of times
cy.intercept('POST', '**/graphql').as('dataStore');
cy.loginByCognitoApi(Cypress.env('cognito_username'), Cypress.env('cognito_password'));
Cypress._.times(11, () => {
cy.wait('#dataStore')
})
Or it might be 10 - looking at the route defn. In any case, experiment. The app should be consistent in the calls it makes.
I had a similar case. What I do is store an array of objects in a different file and each object represents a specific test scenario. That way you can iterate through your test cases an assign an alias dynamically.
So you could do something like this:
beforeEach(function () {
yourArray.forEach((testcase) => {
cy.intercept('POST', '**/graphql').as(`${testcase.testname}datastore`);
cy.loginByCognitoApi(Cypress.env('cognito_username'),
Cypress.env('cognito_password'));
cy.wait(`#${testcase.testname}datastore`);
}
});
If the number of requests aren't consistent, something I've done is the following (I've since put this in a command to use in multiple places):
cy.intercept('POST', '**/graphql').as('dataStore');
cy.loginByCognitoApi(Cypress.env('cognito_username'),Cypress.env('cognito_password'));
cy.get('#dataStore.all').then(xhrs => cy.wait(Array(xhrs.length).fill('#dataStore')));
Doing a wait on the alias with "all" returns all of the calls made to aliased route that Cypress has seen since the alias was made.
#user16695029 is a great solution.
If you run into the issue of API calls not being predictable (kicked off by a timer async etc), then keeping track of API call count might be useful:
at the start of your test code
let responseCounter = 0;
cy.intercept({ method: 'POST', url: '/save', middleware: true }, req => {
req.on('response', (res) => {
responseCounter++;
})
}).as('save')
then later
let expectedSaveCount = 12;
Cypress._.times(expectedSaveCount - responseCounter, () => {
cy.wait('#save')
})
cy.get('#save.all').should('have.length', expectedSaveCount)

Exit Event / Welcome Event Not Firing

We're trying to get some events/messages to post when a user exits a chatbot window (or the site) (or a welcome message), but so far the events are not firing.
I can see within Inspector tools:
Screen Shot 2020-02-18 at 3 15 39 PM
Various activities/conversations are created, the chatbot works, but no welcome/exit events are triggered.
The code we're using is nearly if not identical to documentation code here: https://github.com/microsoft/BotFramework-WebChat/blob/master/docs/WELCOME_MESSAGE.md
and here: How to handle user leaving conversation
I have a function that fires when the window is closed, as follows:
const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => async action => {
return next( action );});
window.addEventListener( 'sendEventActivity', ( { data } ) => {
store.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'user_event',
value: {
name: 'end_conversation',
value: 'user ended conversation'
},
text: 'The user has left the conversation.'
}
})
});
function exitEvent(){
const eventSendActivity = new Event( 'sendEventActivity' );
eventSendActivity.data = 'User left conversation';
window.dispatchEvent( eventSendActivity );
console.log('Exit Event Submitted (hopefully)');
}
exitEvent();
I have tried other variations, defining the store earlier, above render chat, after render chat, sending welcome messages from various locations and at various times but can't seem to get it to send.
We are using https://cdn.botframework.com/botframework-webchat/latest/webchat.js
Any idea what the issue might be? Not sure where we are going wrong or why it's not firing - copying in theory known to be working code straight into our code doesn't seem to do the trick.
Thanks in advance and please let me know if I have failed to include any necessary details- new to chatbot and do not post much on github. Many thanks,
EDIT:
I was able to marry the aforementioned code and code from here: https://github.com/microsoft/BotFramework-WebChat/issues/2120#issuecomment-516056614 in order to achieve what I wanted. I'll post below in case it helps anyone else...
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join'
}
});
}
return next(action);
});
window.addEventListener( 'sendEventActivity', ( { data } ) => {
store.dispatch( {
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/exit'
}
} );
} );
document.getElementById("action_menu_btn").addEventListener( 'click', function() {
const eventSendActivity = new Event( 'sendEventActivity' );
eventSendActivity.data = 'User left conversation';
window.dispatchEvent( eventSendActivity );
console.log('End Converstaion Event Fired');
});
Cheers!
I failed to mention this in the other post (I'll update it), but the reason the code works is because of the window.onbeforeunload() function. Without it, the window closes before any code can finish executing. The result being no event is created, is caught by a listener, nor is sent via the Web Chat store to the bot.
Here, using the above, refreshing the page produces the "User left conversation" activity.
Also, something to note, any function you create and pass thru like you have with exitEvent() is going to run as soon as the page loads. Take the following code which gets the user's location via the browser (placed just before the closing </script> tag). As you can see, it's loading even before Web Chat. If you are wanting a function to run according to some activity passed from the bot, then utilize either the store's actions (i.e. DIRECT_LINE/INCOMING_ACTIVITY, or some other) or via the available middleware.
let geoLoc = async () => {
await navigator.geolocation.getCurrentPosition(position => {
console.log('Latitude: ', position.coords.latitude);
console.log('Longitude: ', position.coords.longitude);
});
}
geoLoc();
Regarding a welcome message, you have two options. Either send as an activity from your bot (reference this sample) or initiate an event on your page after some initial activity is received (reference this sample).
Lastly, I would recommend getting the code working as-is before tinkering with it. This usually trips me up, so thought I'd pass it along.
Hope of help!

Integration test redux-observable that makes multiple ajax requests with debounce

I have a redux-observable epic that polls an endpoint, getting progress updates until the progress is 100%. The polling interval is acheived using debounceTime like so:
function myEpic(action$, store, dependencies) {
return action$.ofType('PROCESSING')
.do(action => console.log(`RECEIVED ACTION: ${JSON.stringify(action)}`))
.debounceTime(1000, dependencies.scheduler)
.mergeMap(action => (
dependencies.ajax({ url: action.checkUrl })
.map((resp) => {
if (parseInt(resp.progress, 10) === 100) {
return { type: 'SUCCESS' };
}
return { checkUrl: resp.check_url, progress: resp.progress, type: 'PROCESSING' };
})));
}
This works fine but I'd like to write an integration test that tests the state of the store when progress is at 25%, then at 50%, then at 100%.
In my integration tests I can set dependencies.scheduler to be new VirtualTimeScheduler().
This is how I'm trying to do it at the moment (using jest):
describe('my integration test', () => {
const scheduler = new VirtualTimeScheduler();
beforeEach(() => {
// Fake ajax responses
const ajax = (request) => {
console.log(`FAKING REQUEST FOR URL: ${request.url}`);
if (request.url === '/check_url_1') {
return Observable.of({ progress: 25, check_url: '/check_url_2' });
} else if (request.url === '/check_url_2') {
return Observable.of({ progress: 50, check_url: '/check_url_3' });
} else if (request.url === '/check_url_3') {
return Observable.of({ progress: 100 });
}
return null;
};
store = configureStore(defaultState, { ajax, scheduler });
});
it('should update the store properly after each call', () => {
store.dispatch({ checkUrl: '/check_url_1', progress: 0, type: 'PROCESSING' });
scheduler.flush();
console.log('CHECK CORRECT STATE FOR PROGRESS 25');
scheduler.flush();
console.log('CHECK CORRECT STATE FOR PROGRESS 50');
scheduler.flush();
console.log('CHECK CORRECT STATE FOR PROGRESS 100');
});
});
My expected output would be:
RECEIVED ACTION: {"checkUrl":"/check_url_1","progress":0,"type":"PROCESSING"}
FAKING REQUEST FOR URL: /check_url_1
CHECK CORRECT STATE FOR PROGRESS 25
RECEIVED ACTION: {"checkUrl":"/check_url_2","progress":25,"type":"PROCESSING"}
FAKING REQUEST FOR URL: /check_url_2
CHECK CORRECT STATE FOR PROGRESS 50
RECEIVED ACTION: {"checkUrl":"/check_url_3","progress":50,"type":"PROCESSING"}
# CHECK CORRECT STATE FOR PROGRESS 100
But instead the output I get is
RECEIVED ACTION: {"checkUrl":"/check_url_1","progress":0,"type":"PROCESSING","errors":null}
FAKING REQUEST FOR URL: /check_url_1
RECEIVED ACTION: {"checkUrl":"/check_url_2","progress":25,"type":"PROCESSING","errors":null}
CHECK CORRECT STATE FOR PROGRESS 25%
CHECK CORRECT STATE FOR PROGRESS 50%
CHECK CORRECT STATE FOR PROGRESS 100%
At which time the test finishes. I'm configuring the store so that I can mock ajax requests and the scheduler used for debounceTime like as recommended here
So my question is how can I test the state of my store after each of the three ajax requests?
Interestingly enough, I played around with your code and am fairly confident you just found a bug in the debounceTime operator, which causes the apparent swallowing the scheduled debounce. The bad news is that even if that bug is fixed, you're code still wouldn't do what you're looking for order wise.
Bear with me as shit is about to get real:
Epic receives action PROCESSING and schedules debounce, yielding execution to your test
Your test calls scheduler.flush() and the VirtualScheduler executes the scheduled debounce work, which will pass along the original PROCESSING action to the mergeMap
Fake ajax is made, which synchronously emits a response
Response is mapped to the second PROCESSING action
Your epic emits that second action synchronously
The second action is recursively received by your epic and given to the debounce
The debounceTime operator now schedules that second action on the VirtualScheduler but the debounceTime operator is in the middle of executing the previously scheduled work still from the first action.
The call stack unwinds a bunch up until it reaches inside the previously scheduled debounce work from the first action that had just next()'d the first action. The rxjs code for debounceTime then sets this.lastValue = null and this.hasValue = false This is the rxjs bug, it needs to be done before nexting into the destination
The stack unwinds some more to the running flush() method of the VirtualScheduler, which now dequeues the second scheduled debounced action because it was added the scheduled work array synchronously, before this the flushing finished. Remember, we've only called scheduler.flush() ONCE so far, which is the function we're in back in at this point.
The second scheduled debounce work is run, but this.hasValue === false because the first scheduled one set it, so the debounceTime operator does not emit anything.
Stack unwinds to our first scheduler.flush()
We console.log('CHECK CORRECT STATE FOR PROGRESS 25')
All the other scheduler.flush() calls do nothing as there's nothing scheduled.
This is technically a bug, but it's not surprising that no one has run into it since running debounce synchronously without any delay defeats the point of it, except when you're testing, of course. This ticket is basically the same thing and OJ says RxJS doesn't make reentrancy guarantees, but I that might be up for debate in this case. I've filed a PR with the fix to discuss
Remember, this bug wouldn't have solved your underlying question about the ordering, but would have prevented the actions from being swallowed.
Off the top of my head I'm not sure how you would do what you'd like to do specifically if you want to maintain 100% synchronous behavior (VirtualScheduler). You'd need some way of yielding to your test in between debounces. For me when and if I write integration tests I mock out very little, if anything. e.g. let the debounces actually debounce either naturally or by mocking out setTimeout to advance them quicker but still keeping them async which will yield back to your test allowing you to check the state, but making your test also async.
For anyone wanting to reproduce, here's the StackBlitz code I used
The answer was to re-write the test asynchronously. Also note-worthy is that I had to mock the ajax requests by returning an Observable.fromPromise rather than just a regular Observable.of, otherwise they would still get swallowed up by the debounce. Something along these lines (using jest):
describe('my integration test', () => {
const scheduler = new VirtualTimeScheduler();
beforeEach(() => {
// Fake ajax responses
const ajax = request => (
Observable.fromPromise(new Promise((resolve) => {
if (request.url === '/check_url_1') {
resolve({ response: { progress: 25, check_url: '/check_url_2' } });
} else if (request.url === '/check_url_2') {
resolve({ response: { progress: 50, check_url: '/check_url_3' } });
} else {
resolve({ response: { progress: 100 } });
}
}))
);
store = configureStore(defaultState, { ajax, timerInterval: 1 });
});
it('should update the store properly after each call', (done) => {
let i = 0;
store.subscribe(() => {
switch (i) {
case 0:
console.log('CHECK CORRECT STATE FOR PROGRESS 0');
break;
case 1:
console.log('CHECK CORRECT STATE FOR PROGRESS 25');
break;
case 2:
console.log('CHECK CORRECT STATE FOR PROGRESS 50');
break;
case 3:
console.log('CHECK CORRECT STATE FOR PROGRESS 100');
done();
break;
default:
}
i += 1;
});
store.dispatch({ checkUrl: '/check_url_1', progress: 0, type: 'PROCESSING' });
});
});
I also set the timer interval to 1 by passing it as a dependency. In my epic I set it like this: .debounceTime(dependencies.timerInterval || 1000)

Wait for an ajax request to complete in React?

Below is my react code I want that firstly the ajax code should execute then the rest of the code should execute.
expected output in console:
inside ajax
outside ajax
current output in console :
outside ajax
inside ajax
import React from 'react';
import request from 'superagent'
const UserItems = () => {
request.get('http://localhost:4000/user/1/items.json')
.then((res, err) => {
if (err) {
console.log("errror found")
}
var data = JSON.parse(res.text)
console.log("inside ajax")
console.log(data)
})
console.log("outside ajax")
console.log(data)
};
export default UserItems;
Any suggestion !!!
As hainguyen points out, ajax is typically asynchronous so the code afterwards will run until the request is complete, at which time the inner function is executed. So the outer console logs will almost certainly run first in your code. While there are ways around this as hainguyen points out, most recommend against it. Ajax is something which takes time, and therefore your code structure should reflect that. If you ever find yourself wanting to run code while the ajax request is in process, you might dislike a synchronous structure. My "I wait for no one" log shows the power of an asynchronous approach since that logic will run quickly while you would normally be waiting on the request without being able to do anything.
Rather than make it synchronous why not use functions to handle the asynchronous behavior better like wrapping whatever you want to run after the inside console log in a function: (I called it outside()) This will output "inside ajax", "outside ajax". This way you can create dependencies on your ajax return and still have the option for running stuff in the meantime.
import React from 'react';
import request from 'superagent';
const UserItems = () => {
request.get('http://localhost:4000/user/1/items.json')
.then((res, err) => {
if (err) {
console.log("errror found");
}
var data = JSON.parse(res.text);
console.log("inside ajax");
console.log(data);
outside();
});
function outside(){
console.log("outside ajax");
console.log(data);
}
console.log("I wait for no one, run me as quick as possible!");
};
export default UserItems;
I don't know about request library but ajax is async by default. If you want ajax perform sync request, you should do something like this:
function getRemote() {
return $.ajax({
type: "GET",
url: remote_url,
async: false
}).responseText;
}
Important line: async: false

Resources