Let's says we have a UsersIndexRoute where we load all users.
model() {
return this.store.findAll('users');
}
When we load the page for the first time (hard reload) and get a HTTP 500 errorback we get this error in the ApplicationRoute's errors() and can render a error page and everything is fine.
But:
Let's says we already loaded the Ember App but only loaded a subset of all users, go to the /users page and call the findAll again, Ember immediately gives back the subset of users we already loaded in the store and fetches all the other users in a background request.
Now in our case we get a HTTP 500 error back in the backgroundReload, but it seems like https://github.com/emberjs/data/blob/master/packages/ember-data/lib/system/store.js#L1027 doesn't return the promise array back and we can't catch the error in our findAll method anymore, or receiving any error in the ApplicationRoute's error().
My question is: how and where can I catch errors from backgroundReload?
You can catch any error using .then() method:
model() {
return this.store.findAll('users')
.then(null, (error) => {/*do smth*/});
}
Here is the GH Issue that discusses the topic and also gives a "solution" to the problem: https://github.com/emberjs/data/issues/3809
Related
I'm trying to overwrite an existing command in Cypress.io. I'm looking to log() a route response's status & the route's url to extend the functionality of the built-in route(). Unfortunately, I get this message The route undefined had a undefined status code. in the console. Note, I'm using the browser's console momentarily. Eventually, I'll use the log() built-in method. This is what I have tried so far:
cypress/support/commands.js
Cypress.Commands.overwrite('route', (originalFn, response) => {
console.log(`The route ${response.url} had a ${response.status} status code.`);
return originalFn(response);
});
Update:
I'm getting the route now, but I still don't get response or status. This is my current code:
Cypress.Commands.overwrite('route', (originalFn, url, response) => {
console.log(`The route ${url} had ${response} status code`);
return originalFn(url, response);
});
When using the pattern cy.route(method, url, response), the response parameter is use to stub the call and return the supplied response to your app, see (route() - Arguments)
response (String, Object, Array)
Supply a response body to stub in the matching route.
Note that creating an overwrite of cy.route() will be hooking into the route configuration, not the capture of the route.
The pattern cy.route(options) has an onResponse option which can be used to console.log() the response, but cy.log() does not work there, probably because we invoke a command inside a command.
Cypress.log() can be used instead.
cy.route({
url: 'http://example.com',
method: 'GET',
onResponse: (response => {
const message = `The route '${response.url}' had a ${response.status} status code.`;
const log = Cypress.log({
displayName: 'Route debugging',
message: message,
consoleProps: () => {
// return an object which will
// print to dev tools console on click
return {
message: message,
}
}
})
log.finish(); // remove log spinner
})
})
/*
Command log output:
ROUTE DEBUGGING
The route 'http://example.com' had a 200 status code.
*/
Depending on what you're trying to achieve, there are a couple of options. Richard's answer above describes one approach - I'll attempt to cover some others.
(Note: The Cypress documentation at https://docs.cypress.io/ probably will give you a better understanding than this answer. I'll try to link the relevant articles inline)
(You can skip ahead to the section on 'Inspecting Api Responses' if you don't care why your code isn't working)
What's happening in your code
Let's look at the example code from https://docs.cypress.io/api/commands/route.html#Examples
cy.server()
cy.route('**/users').as('getUsers')
cy.visit('/users')
cy.wait('#getUsers')
Without your overwrite, cy.route here just registers the route, so you can wait for it later (Remember, cy.route does not make any api calls itself). With your overwrite, cy.route is completely replaced with your callback:
Cypress.Commands.overwrite('route', (originalFn, url, response) => {
console.log(`The route ${url} had ${response} status code`);
return originalFn(url, response);
});
So when cy.route('**/users') is called, it will instead evaluate
(originalFn, url, response) => {
console.log(`The route ${url} had ${response} status code`); // Logs "The route **/users had undefined status code"
return originalFn(url, response); // Registers the route with an mock value of undefined
})(originalCypressRouteFn, '**/users')
You can see why response is undefined - it's not passed in to the route call at all, since the request hasn't even been made.
Note that if we were attempting to mock the call instead (See https://docs.cypress.io/api/commands/route.html#With-Stubbing)
cy.route('https://localhost:7777/surveys/customer?email=john#doe.com', [
{
id: 1,
name: 'john'
}
])
You would instead log
"The route https://localhost:7777/surveys/customer?email=john#doe.com had [object Object] status code"
Inspecting Api Responses
If you just want to inspect the response from an api, you can use the using the built-in debugging tools (after calling cypress open). The browser's Network tab is available (which will record all requests made during a given test run), and you can additionally click on the response recorded in the left panel, which will log the request and response to the browser console.
If you're attempting to assert on the response to an api call, you can use cy.wait (See https://docs.cypress.io/guides/guides/network-requests.html#Waiting) to get access to the underlying xhr request after it finishes:
cy.wait('#apiCheck').then((xhr) => {
assert.isNotNull(xhr.response.body.data, '1st API call has data')
})
If you want a record of the APIs calls made during a CLI run (using cypress run), you can:
Print debug info, which will give you a lot of information, including all requests and responses (See https://docs.cypress.io/guides/references/troubleshooting.html#Print-DEBUG-logs): DEBUG=cypress:* cypress run (You can change cypress:* to limit the scope of the debug to just api calls, though I don't know off the top of my head what the namespace you'll want is)
Use a plugin that records all requests (e.g. https://github.com/NeuraLegion/cypress-har-generator)
When using an api I often find myself with a rather complicated error object.
Depending on the API that I am using the error texts are quite helpful and I would actually sometimes like to display them directly to the user. The problem, of course, is that the error objects can look quite differently so it would be very verbose to go through them and pick individual objects in case they exists (dependant on the status code of the error).
Is this just the nature of the error object or is there a better way to do this?
What I do to handle API calls that end up with error is this:
try {
const response = await axios.post("Your URL");
// Your code to handle the result
} catch (error) {
console.log(error.response.data.error)
// Code to display the error to the user
}
error.response.data.error is the actual error message sent from the server, not the error code
Problem:
I am seeing following error in my browser console, I don't want a solution to resolve this error.
I want a solution to remove from the browser console.
GET https://logo.clearbit.com/objectivepartners.com net::ERR_ABORTED 404
I came to following solution which can handle consoling but while using fetch
it is not working:
console.defaultError = console.error.bind(console);
console.errors = [];
console.error = function(){
if (!arguments[0].includes("404")) {
console.defaultError.apply(console, arguments);
}
console.errors.push(Array.from(arguments));
}
fetch("https://logo.clearbit.com/objectivepartners.com").then(response => {
if (response.ok) {
console.log("okay");
}
}).catch(error => {
console.error("404"); // WILL NOT SHOW IN BROUSER CONSOLE
console.error("error"); // WILL SHOW IN BROWSER CONSOLE
});
Here,
I want if arguments include 404 then do not console it in the browser.
But on the fetch request failure, it includes 404 still it consoling, that I do not want to be happening
could it be possible that when fetch fail i can disable using in this code (by changing) or any other way?
Unfortunately, I didn't find any solution to resolve at the client-side or using javascript.
But I resolve this by creating an endpoint to API side and giving URL to that API to check that URL is valid or not, based on API response I handled in fetch
everyone!
I got a problem: I'm trying to validate registration form. Totally, it works ok, but I need to validate form via server. In my case, for example, I need to figure out if email is already taken.
I tried to fetch and async/await syntax, but problem is still the same:
DOMException: "The operation was aborted. "
The way I understand it right now is readableStream (what actual response body is) is locked. So the wrong error is thrown, and I cannot get server response.
try {
const response = await fetch(options.url, options.requestOptions);
const body = await response.json();
if (options.modifyDataCallback instanceof Function) {
body.data = options.modifyDataCallback(body.data);
}
return body.data;
} catch (error) {
throw error;
}
How do I see the solution? I send request and recieve some server error like
code: email_in_use
message: Email '...' is already in use.
Then I need to throw error and catch it in other place in order to show corresponding error message to client.
In browsers network tab I do receive what I want to receive, but can't get the same JSON-response in my code.
Google chrome provided more information: net::ERR_HTTP2_PROTOCOL_ERROR 200.
And the problem was on backend. It is written in C# and API method returned Task. The problem was solved by adding async/await for this method.
I'm using Firebase-Firestore on Javascript (web) with a Progressive web app. I ran into this error:
INTERNAL ASSERTION FAILED: Got result for empty write pipeline
Because Firebase runs asynchronously with XHR requests, it was difficult to determine the exact source of the error - it seemed like any onSnapshot, set or update was throwing this error for me.
And after that first error came a flurry of other errors:
INTERNAL ASSERTION FAILED: AsyncQueue is already failed: Error: FIRESTORE (5.3.0) INTERNAL ASSERTION FAILED: Got result for empty write pipeline
I thought my operation was pretty normal - just using the API set(), update() , onSnapshot() functions when it happened.
It's not a mission critical error - the code runs fine, but I'm hit with a couple thousand errors when I open debug, so it's prohibitive in that regard.
For my PWA I was using a cache-first, web-reupdate model which returns cachedResponse but also fetch()es the response and caches the fetched response.
Anyone have any insights?
It was the PWA! Using the PWA, I was catching all GET requests, including Firebase's own GET's. Filtering to ensure CORS requests don't return from cache fixed the problem.
To solve this, I added this code to my PWA:
self.addEventListener("fetch", event => {
if (event.request.method == "GET") {
event.respondWith(
(async function() {
const cachedResponse = await cache.match(event.request, {
ignoreSearch: true
});
// Returned the cached response if we have one, otherwise return the network response.
if (cachedResponse && event.request.type!="cors") {
//AVOID CORS FOR THINGS LIKE FIREBASE
updateCache(event);
return cachedResponse;
} else return await updateCache(event);
})()
);
} else {
event.respondWith(fetch(event.request));
}
});
If you're new to the PWA space, want to get a jump start to ANY PWA project, or want to just 'share notes', the repo with the full comprehensive PWA file is here: https://github.com/acenturyandabit/genUI/blob/master/Javascript/pwa.js
I've personally put a lot of time into this so I hope it helps :)