I am making an api call from React app with axios.
The user selects 2 values from 2 dropdowns, and the api call is made using these 2 values. Normally the response will be an object, but occassionally if the user selects 2 values which dont have a match, then it wont return anything.
I want to ensure a message is displayed if nothing exists for those 2 items.
Currently in my axios response if nothing is return I get a long bunch of what looks like the index html page.
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.adebe8fe.js"></script><link href="/static/css/main.aa245bf1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
I am getting the data from a c# controller,
[HttpGet("search/{antifungal}/{interacting}")]
public async Task<ActionResult<DrugInteractionDTO>> getAntifungalInteraction(string antifungal, string interacting)
{
var interactions = await _context.DrugInteractions
.Include(di => di.AntifungalAgent)
.Include(di => di.InteractingDrug)
.Where(di => di.AntifungalAgent.Name.ToLower() == antifungal.ToLower())
.Where(di => di.InteractingDrug.GenericName.ToLower() == interacting.ToLower())
.Select(x => new DrugInteractionDTO
{
Severity = x.Severity,
SeverityAsString = x.Severity.ToString(),
ProDetailedInformation = x.ProDetailedInformation,
BasicDetailedInformation = x.BasicDetailedInformation,
Antifungal = x.AntifungalAgent.Name,
InteractingDrug = x.InteractingDrug.GenericName,
ID = x.ID
}).FirstOrDefaultAsync();
if (interactions == null) return NotFound();
return interactions;
}
Using swagger if I enter 2 items in the query that dont exist I get
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"traceId": "00-29b4bb56b99fe26416be4e3c09add6b7-dc13efbf731e6a72-00"
}
So I would have thought calling console.log(response.data) in my axios call would log 404, but it just gives undefined`
This is currently what I have in React,
const getInteractionDetails = () => {
agent.drugInteractions.getIndividual(antifungalDrug, interactingDrug)
.then((response) => {
console.log(response.status)
if(response.status === 404){
setError('No interaction exists')
} else {
setInteractionDetails(response)
}
})
.catch(error => console.log(error))
}
How come status isnt being shown in my axios response?
Related
I'm using next js 13 along with Jest and react-testing-library for testing. I have a page with a form that i'm trying to test. I'm using react-hook-form.
export default function FormPage() {
const [isSuccess, setIsSuccess] = useState()
const submitForm: SubmitHandler<T> = async (data) => {
// call an api route here to send data to db
if (response.status == 200) setIsSuccess(true)
else setIsSuccess(false)
}
return (
<>
<form onSubmit={handleSubmit(submitForm)}>
// inputs here
</form>
{isSuccess ? <SuccessAlert /> : <Error />}
</>
)
}
I want to check if the success alert appears after the form is successfully submitted. I could mock the global.fetch but my problem is that there are two fetch happening in this page. A location input is also making fetch calls to give location suggestions to the user as they type. So when I mock global.fetch for the location input, it appears that it's also replacing the fetch call inside the submitForm function, hence, submitting the form doesn't really do anything.
Here's how I mocked the global.fetch for the location input:
describe("Form" , () => {
beforeEach(() => {
render(<FormPage/>)
global.fetch = jest.fn(() =>
Promise.resolve({
status: () => 200,
json: () =>
Promise.resolve({
data: { suggestions: SAMPLE_LOCATION_SUGGESTIONS },
}),
})
) as jest.Mock;
})
it("should show success alert after successfully submitting form", async () => {
await act(() => // fill up the form)
fireEvent.click(Submitbutton)
expect(scree.getByTestId("success-alert")).toBeInThisDocument()
})
})
Running screen.debug() just before the assertion shows that there are no errors appearing upon submission so the form is already valid. But it appears that calling the api for form submission does not happen at all. I'm guessing it's because of my initial mocking of fetch in beforeEach(). But i'm not sure how should should I mock 2 fetch inside a component.
I created a ngrx effect that's responsible for sending a POST request to a back end. now i want to change the implementation little bit. if the post request is successful I want to trigger another action that responsible update my ngrx store. but I couldn't figure out how to do that.
I tried to use switch map and merge map but didn't work.
creatTour$ = createEffect(() =>
this.actions$.pipe(
ofType(TourAction.createTour),
mergeMap((action) => {
const payload = action.tour;
const endpoint = environment.urls.tour.replace("{tourProviderId}", "1");
const request = new ServiceRequest(endpoint, 'POST', payload, options);
return this.requestHandlerService.invoke(request).pipe(
map((sucessResponce) => {
if (sucessResponce.code === 200) {
TourListAction.updateTourList({ tour: [tour] }) // i want to trigger this action and
// below action
}
return TourAction.createTourSucess({ responce: sucessResponce.message })
}),
catchError(err => {
const errorMessage = JSON.stringify(err);
console.log(errorMessage);
return of(TourAction.createTourFail({ errorMessage }))
})
)
})
)
);
i tried this way too
return [TourAction.createTourSucess({ responce: sucessResponce.message }
TourListAction.updateTourList({ tour: [tour] })]
it throws this error
Property 'type' is missing in type '(({ responce: string; }
& TypedAction<"[Tour] Create Tour Success">) | ({ tour: Tours[]; } &
TypedAction<"[Tour List] Tour List Update">))[]' but required in type
'Action'.
is this the better way to do this.i saw there is new thing called entity should I use that for this implementation?
Why not update your state on the createTourSucess action?
You can also return multiple actions:
.pipe(
switchMap(() =>
return [
TourListAction.updateTourList({ tour: [tour] }) ,
TourAction.createTourSucess({ responce: sucessResponce.message })
]
)
)
https://medium.com/#amcdnl/dispatching-multiple-actions-from-ngrx-effects-c1447ceb6b22
You can return multiple actions from your effect, they will all be dispatched.
See https://medium.com/#tanya/understanding-ngrx-effects-and-the-action-stream-1a74996a0c1c
For your code:
return successResponse.code === 200 ? [
createTourUpdateAction(tour),
TourAction.createTourSuccess
] : [TourAction.createTourSuccess]
All POST and PUT XMLHttpRequest made into Cypress have recently started throwing 417 Expectation Failed. However all these work on the web application when I navigate through it manually.
All my code used to work well in past without any issue.
I read about this error over internet and I'm not sure if this issue exists on the application under test, or on some firewall policy or there is some setting in Cypress which can fix it.
Cypress.Commands.add("Post_Client", () => {
cy.fixture(Cypress.env("ClientInputFile")).then(clientoBJ => {
cy.fixture(clientoBJ.imagePath, "binary").then(imageBin => {
Cypress.Blob.binaryStringToBlob(imageBin, clientoBJ.imageType).then(
blob => {
const xhr = new XMLHttpRequest();
const data = new FormData();
data.set(clientoBJ.nameatr, clientoBJ.nameVal);
data.set(clientoBJ.imageatr, blob);
xhr.open(
"POST",
Cypress.env("APIBaseURL") + Cypress.env("ClientPostURL"),
false
);
xhr.setRequestHeader("accept", "application/json");
xhr.setRequestHeader("access-token", accesstoken);
xhr.setRequestHeader("client", client);
xhr.setRequestHeader("expiry", expiry);
xhr.setRequestHeader("token-type", tokentype);
xhr.setRequestHeader("uid", uid);
xhr.onload = function() {
if (this.status === 201) {
cy.writeFile(
Cypress.env("ClientOutputFile"),
JSON.parse(this.responseText)
);
cy.readFile(Cypress.env("IDStore")).then(obj => {
obj.clientID = JSON.parse(this.responseText).client.id;
cy.writeFile(Cypress.env("IDStore"), obj);
});
}
};
xhr.send(data);
}
);
});
});
});
And then it is called in a Test
it.only("CLIENT API POST TEST", () => {
cy.Post_Client();
});
This stands fixed now.There were two problems causing this and both were at the application layer.
Problem# 1 - Somehow we chose 417 as the error code for any unhandled events.
Fix - We are now using 422 error code for unprocessable entities
Problem# 2 - A formData append method has three params -(name, value, filename) where filename is optional. It is made mandatory in the application code recently.
fix -
data.set(
clientoBJ.imageatr,
blob,
clientoBJ.imagePath.substring(
clientoBJ.imagePath.lastIndexOf("//") + 2
)
);
I am using wordpress rest api and angular2 to build simple one page app. I created a custom post type with toolset. All is working fine and I can see the data returning fine.
http://tncorp.biffapps.com/wp-json/wp/v2/downloads/?filter[product]=Pico
Screenshot
When try to request the data in my Angular application, the response body is empty.
Response
_body
:
"[]"
headers
:
Headers
ok
:
true
status
:
200
statusText
Does anyone know why this is happing?
Code for the http get:
getProductDownloads($id): Observable<any> {
this.ProductsDownloads = this.http.get(this.wpurl + 'downloads/?filter[product]='+$id)
.map(res => {
console.log('GET DOWNLOAD',res)
return this.ProductsDownloads = this.extractData(res)
})
.catch(this.handleError);
return this.ProductsDownloads;
}
You want to return the Observable itself:
getProductDownloads($id): Observable<any> {
return this.http.get(this.wpurl + 'downloads/?filter[product]='+$id)
.map(res => {
console.log('GET DOWNLOAD',res)
return this.ProductsDownloads = this.extractData(res)
})
.catch(this.handleError);
}
Then when you're calling it, you subscribe to the Observable.
// I'm using "this" here, but if you have it in a -service- you'd put that there
this.getProductDownloads(id).subscribe(result => {
this.products = result;
});
Also, you could do it the following way and incorporate the | async pipe in your template instead of manually subscribing & unsubscribing.
this.products = this.getProductDownloads(id);
// template:
{{ products | async }}
I have a problem with angular2 http response.
I want to catch the error in my component.
How does my app work.
In my Component, I Call a function in a personal service :
var response = this.apiUser.login(username, password);
alert(response);
In my Service, I try to auth :
this.http.post(this.httpApiAdress + '/' + this.httpUserAutenticate, body, { headers: contentHeaders })
.subscribe(
response => {
localStorage.setItem('id_token', response.json().token);
this.router.navigate(['home']);
},
error => {
return error.json();
},
() => { }
);
When the auth is ok, all work fine. But when the Auth fail, i can't catch the response in my Component.
(Its undefinied because the alert is executed before the http call...)
Can u help me please !!! (It was working when all the code was only in my Component, but I wanted to slip my code...)
Ty.
Return the observable by using map() instead of subscribe()
return this.http.post(this.httpApiAdress + '/' + this.httpUserAutenticate, body, { headers: contentHeaders })
.map(
response => {
localStorage.setItem('id_token', response.json().token);
this.router.navigate(['home']);
},
);
and then use subscribe where you want to execute code when the response or error arrives
var response = this.apiUser.login(username, password)
.subscribe(
response => alert(response),
error => alert(error),
);