Cypress: extract value from JSON body to a variable - javascript

I am using cypress.io to test an API(Created using Node.js). I want to extract value from JSON response of the API and save it to a variable.
I have tried solutions mentioned in the below links it did not work:
Cypress - get value from json response body
Below is the code i am using to test the API:
/// <reference types="cypress" />
describe("Testing Provider Catalog API", () => {
it("Provider Catalog API GET Request", () => {
cy.request('GET', 'v1/providers')
.then((response) => {
expect(response).to.have.property('status', 200)
expect(response.body).to.not.be.null
// expect(response.body.providers).to.have.length(1)
})
cy.screenshot()
})
it("Provider Catalog API POST Request", () => {
const provider = {
"type": "loadboard",
"name": "123loadboard"
};
cy.request('POST', 'v1/providers', provider)
cy.screenshot()
})
it("Provider Catalog API PUT Request", () => {
const provider = {
"type": "loadboard",
"name": "123loadboard"
};
cy.request('PUT', 'v1/providers/61a54a66a2b734859481931c', provider)
cy.screenshot()
})
it("Provider Catalog API DELETE Request", () => {
cy.request('DELETE', 'v1/providers/61a68e7ca6011e605029191b')
cy.screenshot()
})
})
Below is the code that i am using
var providerId
cy.wait('#newObject').then((response) => {
expect(response.status).to.eq(201)
expect(response.responseBody).to.have.property('_id')
const body = (response.responseBody)
providerId = body['_id']
})
cy.get(someInput).type(newId)
Sample output of the API:
{
"_id":"61a54ba1a2b7348594819323",
"type":"loadboard",
"name":"123loadboard",
"__v":0
}
I want to store the value of the _id in a variable and use it later. I have been trying to for the last couple of days and nothing seems to work. Can anyone please help me. Thanks in advance.

The recommended way to use variables with cypress is with aliases. See docs here.
In your code, you can wrap() your _id and save it as an alias, then call your alias somewhere else in your code:
cy.wait('#newObject').then((response) => {
expect(response.status).to.eq(201)
expect(response.responseBody).to.have.property('_id')
cy.wrap(response.responseBody._id).as('newId')
})
// then later in your code use:
cy.get('#newId').then((newId) => {
cy.get(someInput).type(newId)
})
You could also type() your _id inside your wait():
cy.wait('#newObject').then((response) => {
expect(response.status).to.eq(201)
expect(response.responseBody).to.have.property('_id')
cy.get(someInput).type(response.responseBody._id)
})
Or you can use cypress global environmment object Cypress.env(). See docs here.
cy.wait('#newObject').then((response) => {
expect(response.status).to.eq(201)
expect(response.responseBody).to.have.property('_id')
Cypress.env('newId', response.responseBody._id)
})
// then later in your code use:
cy.get(someInput).type(Cypress.env('newId'))

Related

Cypress V10. Not Reading data in BDD test: TypeError: Cannot read properties of undefined (reading 'mobileHandset')

I hope someone can help, I've just converted a Cypress Mocha framework to BDD. Before converting it was running perfectly and the test was running smoothly. Now I've converted it I seem to be getting an error message Cannot read properties of undefined (reading 'mobileHandset'). I never had this issue before so I'm very confused. here is the code and watch this video
Feature:
Feature: End to End Shopping Purchase Validation
Registered user will be able to purchase an item and have it shipped to their country
Scenario: Customer Purchase and delivery
Given I am on the eCommerce page
When I add items to cart
And I confirm shopping cart total
Then I select my delivery country and see a thank for your order notification
Step Definition
import { Given, And, Then, When } from "#badeball/cypress-cucumber-preprocessor";
import Homepage from '../../../support/pageObjects/Homepage'
import orderSummaryPage from '../../../support/pageObjects/orderSummaryPage'
import completeOrderPage from '../../../support/pageObjects/completeOrderPage'
const data = require ('../../../fixtures/example.json');
const homepage = new Homepage()
const StartCheckout = new orderSummaryPage()
const CompleteOrder = new completeOrderPage()
Given(/^I am on the eCommerce page$/, () => {
cy.visit(``+"/angularpractice/")
});
When(/^I add items to cart$/, function() {
homepage.getShopTab().click({force:true})
this.data.mobileHandset.forEach(function(element) {// this custom commad will add items to your cart
cy.AddToCart(element)
});
StartCheckout.getBasketCheckoutButton().click()
});
When(/^I confirm shopping cart total$/, () => {
let sum=0
CompleteOrder.getProductCost().each(($e1, index, $list) =>{
const unitCost=$e1.text()
let res= unitCost.split(" ")
res= res[1].trim()
sum=Number(sum)+Number(res)
}).then(function()
{
cy.log(sum)
})
});
Then(/^I select my delivery country and see a thank for your order notification$/, () => {
StartCheckout.getStartCheckoutButton().click()
CompleteOrder.getShippingCountry().type('United Kingdom')
CompleteOrder.getShippingCountryConfirm().click()
CompleteOrder.getTermsConditionsCheckbox().click({force: true})
CompleteOrder.getPurchaseButton().click()
CompleteOrder.getPurchaseAlert().then(function(element){
const actualText= element.text()
expect(actualText.includes('Success')).to.be.true
})
});
Here is the data
{
"name": "MY_NAME",
"gender": "Female",
"mobileHandset": ["Blackberry", "Nokia Edge"]
}
BeforeEach
beforeEach(function()
{
cy.fixture('example').then(function(data){
this.data=data
})
})
After discussion I moved the BeforeEach file to Support. Still getting the original error
You don't need to import the data fixture if you already have it in the cypress/fixtures folder.
You can load the fixture in the Before hook before your tests.
import {
Given,
And,
Then,
When,
Before
} from "#badeball/cypress-cucumber-preprocessor";
//...
Before(function() {
cy.fixture('example').then((data) => {
this.data = data;
});
});
//...
Your beforeEach() should be working, but it's not necessary you can just refer to data instead of this.data.
const data = require ('../../../fixtures/example.json'); // data available anywhere in this step
...
When(/^I add items to cart$/, () => {
...
data.mobileHandset.forEach(element => {
cy.AddToCart(element)
})
...
})
The convention is to use cy.fixture()
When(/^I add items to cart$/, () => {
...
cy.fixture('example.json').then(data => { // no ../.. needed
data.mobileHandset.forEach(element => {
cy.AddToCart(element)
})
})
...
});

Define response structure in Adonisjs with Middleware

I want to define the response structure of my requests in the simplest way, and the first thing that comes in my mind to do this is a middleware.
My endpoints are returning the response content correctly:
{{base_url}}/users returns a list of users:
{
[
{
"id": 44,
"name": "some name"
[...]
}
]
}
What I want to do (in all requests) is to add the fields status and data (or any other I'd like to add), like this:
{
"status": 200,
"data": [
{
"id": 44,
"name": "some name"
[...]
}
]
}
I've created a middleware that waits for the resolution but I'm not able to get the content nor add some property to it.
[...]
async handle ({request, response}, next) {
await next()
const content = response._lazyBody.content
content.status = response.response.statusCode
}
[...]
I know this will not work but I want something similar to this. I've looked in Adonis docs and forum, but no answers fit to my needs.
Any help will be welcome
You can extend Response By extending the core. The simplest way is to create a file inside start folder and name it hooks.js and copy and paste the content below inside it:
const { hooks } = use('#adonisjs/ignitor')
const Response = use('Adonis/Src/Response')
hooks.after.providersBooted(() => {
Response.macro('customJson', function (status, data) {
this.status(status).json({
status,
data
})
})
})
this piece of code extends the Response module and add customJson method to it which takes two arguments, status and data, and send them back to the client.
And here you can see how to use it:
Route.get('/users', async ({ response }) => {
let status = ''// whatever you want
let data = ''// whatever you want
return response.customJson(status, data)
})

Not able to autheticate google cloud vision api . How to autheticate it to use it further

My Code looks like this :-
var vision = require('#google-cloud/vision');
handleSubmit = () =>{
console.log("encoded string submitted=",this.state.files);
this.useVisionCloud();
}
useVisionCloud = () =>{
const client = new vision.ImageAnnotatorClient();
const request_body = {
"requests": [
{
"image": {
"content": this.state.files
},
"features": [
{
"type": "TEXT_DETECTION"
}
]
}
]
};
client.textDetection(request_body).then(response => {
console.log("text got=",response);
// doThingsWith(response);
})
.catch(err => {
console.log("error got=",err);
});
}
I already tried setting environment variable but didn't work .
I have also created service account and downloaded the file.json
but dont know how to use it for authentication
im getting the following error :-
Uncaught Error: {"clientConfig":{},"port":443,"servicePath":"vision.googleapis.com","scopes":["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/cloud-vision"]}You need to pass auth instance to use gRPC-fallback client in browser. Use OAuth2Client from google-auth-library.
on triggering a post request to Google API .
Final Query is :- I am not able to understand how to authenticate API so that i can further use it to detect text in my images
Set the env variable eg:
export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"
I would recommend having a separate backend that calls vision api. Then have the javascript code in your browser call your backend.

Trying to Map Yelp API repsonse

I am using the Yelp API (by making requests to it using https://cors-anywhere.herokuapp.com/ as a proxy—because the Yelp API itself isn’t CORS-enabled) to attempt to create an app very similar to a Yelp search for my own practice. I am able to get the response into my browser's console. The response has an array named businesses with the businesses that match the search. I am trying to use .(map) to map through the businesses array. However, I keep getting Cannot read property 'map' of undefined.
The reponse I receive from the Yelp API is below. Thanks
Yelp API Response Image
Also if there is any other tips about javascript that come to mind when looking at my code please share as I am very early into my programming career.
const Yelp = {
getAccessToken: function() {
if(accessToken) {
return new Promise(resolve => resolve(accessToken));
};
return fetch(accessTokenUrl, {
method: 'POST'
}).then(response => response.json()).then(jsonResponse => {
accessToken = jsonResponse.access_token;
})
},
search: function(term,location,sortBy) {
return this.getAccessToken().then(() => {
const yelpRetrieveUrl = `${corsAnywhereUrl}https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}&sort_by=${sortBy}`;
return fetch(yelpRetrieveUrl, {
headers: {Authorization: `Bearer ${accessToken}`}
});
}).then(jsonResponse => {
if(1 > 0){
console.log('true!!!!');
return jsonResponse.businesses.map(business => {
return {
id: business.id,
imageSrc: business.image_url,
name: business.name,
address: business.location.address1,
city: business.location.city,
state: business.location.state,
zipCode: business.location.zip_code,
category: business.categories,
rating: business.rating,
reviewCount: business.review_count
};
});
} else {
console.log('FALSE')
}
})
}
};
fetch(myRequest).then(function(response) {
var contentType = response.headers.get("content-type");
if(contentType && contentType.includes("application/json")) {
return response.json();
}
throw new TypeError("Oops, we haven't got JSON!");
})
.then(function(json) { /* process your JSON further */ })
.catch(function(error) { console.log(error); });
You might search for the jsonResponse#json function to turn your json dataset into a real object that you can process in JavaScript.
And because you asked for it: As you are using Promises, make use of the Promise#Catch function to handle upcoming errors. Don't let the browser handle them, because they can have different behaviors in different browsers.
And probably remove the 1 > 0 check, because it will always be true, but I think this was only for test purposes.
I hope I could help you! I might append the code later since I'm currently on mobile.

Using Fetch API with Rails application?

I am trying to use the Fetch API with my Rails application. I can pass parameters to the controller as part of a query string, but still can't figure out how to pass JSON data or where to find it in the controller. A sample call looks like the below. Where can I access my test data on in the controller? Happy Sunday :)
export const fetchControllerData = () => {
return fetch('api/users',), {
body: { "test": "test" }
})
.then(res => res.json());
};
I'm in the process of working out my own issues with fetch and Rails. But I'll take a stab at this.
I expect that fetch is using GET as the default method - which won't use the body at all. You will likely need to set the method to be POST to get the body through. Further to that you might need to set the Content-Type header (to application/json) in order to send the data through as JSON.
May be u need to send params in this way for get request and use this link for https://github.com/axios/axios
export const fetchControllerData = () => {
params = { body: { "test": "test" } }
return HTTP.get('api/users', params)
.then((response) => {
if (response.success) {
// do something here
} else {
// handle error condtion here
}
});
}

Categories