I am retrieving the key and trying to pass it in a header while doing GET request, but getting an error.
Utils.js (Here I am retrieving the token)
class Utils {
getKey(){
let key
return cy.request({
method: 'POST',
url: 'http://127.0.0.1:3000/sign-in',
body: {
"password" : "password",
"email" : "email"
},
headers: {
'content-type': 'application/json'
}
}).then((response)=>{
expect(response.body).have.property('access_token')
key = response.body['access_token']
})
return key
}
}
export default Utils
Then I am trying to pass the token in headers
import Utils from '../../fixtures/Utils'
describe("HTTP Example", ()=>{
let utils = new Utils()
it('GET', ()=>{
console.log(utils.getKey())
cy.request({
method: 'GET',
url: 'http://127.0.0.1:3000/users',
headers: {
'Authorization': utils.getKey()
}
}).then((response)=>{
expect(response.body[0]).to.have.property('name', 'Test user')
console.log(response)
})
})
Getting Error: Target cannot be null or undefined.
When you are returning value from a method/function in Cypress, then you have to access the value by chaining only. Below is the snippet which solves your problem. Let me know if it worked or not.
utils.getKey().then(authToken => {
cy.request({
method: 'GET',
url: 'http://127.0.0.1:3000/users',
headers: {
'Authorization': authToken
}
}).then((response) => {
expect(response.body[0]).to.have.property('name', 'Test user')
cy.log(response)
})
})
Related
So the issue i have is i want to be able to call a module function, that will then call cy.request() get the response and feed this to another cy.request() in a nice way.
I want to make this code nicer:
Cypress.Commands.add('createUser', (user) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/tokens',
body: {
email: 'admin_username',
password: 'admin_password'
}
}).then((resp) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/users',
headers: ({ Authorization: 'Bearer ' + resp.body.token }),
body: user
})
})
})
I'd like to to have the two cy.requests within their own functions, e.g getAuthToken() and createUser(), so i can wrap that in either a Cypress.Command, or just a module function and call within the test file
const seedUser = (userObject) => {
getAuthToken().then((token) => {
return createUser(token); //where this would return the created user.
}
}
then used like so in the test file
before(()=>{
let user = seedUser();
//or
let user = cy.seedUser();
}
You can use cy.wrap() to wrap the response of your first request and then you can use it anywhere.
Custom commands:
Cypress.Commands.add('getAuthToken', () => {
cy.request({
method: 'POST',
url: 'https://www.example.com/tokens',
body: {
email: 'admin_username',
password: 'admin_password'
}
}).then((response) => {
cy.wrap(response).as('getAuthTokenResponse')
})
})
Cypress.Commands.add('createUser', (user) => {
cy.get('#getAuthTokenResponse').then((resp) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/users',
headers: ({ Authorization: 'Bearer ' + resp.token }),
body: user
})
})
})
In your Test file you can just add:
cy.getAuthToken()
cy.createUser(user)
I am using Cypress 4.3.0 version, the baseUrl = "https://tenant-demo.somesitedev.net" has been set in cypress.json file. While I am sending the cy.request() command, it is sending multiple request (please see Fig:1) . Also, when I observed the visit command I could see following Original Url, Resolved Url and Redirects. In this scenario, how do I login to the site using cy.request() command.
before(()=>{
cy.visit('/').then(()=>{
cy.get('input[type="hidden"]').invoke('val').then((val)=>{
const token = val;
cy.login(token);
})
})
})
Cypress.Commands.add('login', (token) => {
const username= 'test1.user';
const password= 'somepassword';
const accessToken = localStorage.getItem('tokens');
const cookieValue = document.cookie.split(';');
const configCat = localStorage.getItem('ConfigCat_');
cy.request({
method: 'GET',
url: '/dashboard',
failOnStatusCode: false,
form: true,
body:{
_token: token,
username,
password
},
headers: {
'accept': 'text/html',
'content-type': 'application/x-www-form-urlencoded',
'authorization': `bearer ${accessToken}`,
'ConfigCat_': `${configCat}`,
'cookie': `${cookieValue}`
}
}).then((res)=>{
visitDashboard();
})
})
const visitDashboard = () => {
cy.visit('dashboard')
}
Fig:1
Fig:2
Somehow I managed to find a way to resolve the problem. Since the baseUrl has got some path extension /auth/login, whenever I trigger a cy.request() it was always redirecting back to login page even though the credentials was correct. Also there were two requests in the console.
So the way I did was to send another cy.request() with GET method with body params immediately after the first POST cy.request() with qs parameters. From the request headers I find out there was a 'token' submitted every time when the user login.
If there is another easy way let me know.
Cypress version : 4.4.0
Inside beforeEach(), grab the 'token' value;
beforeEach(() => {
cy.visit('/');
cy.loadTokens();
cy.get('input[name="_token"]').invoke('val').then((val)=>{
const tokenValue = val;
cy.loginRequest(tokenValue);
})
})
Following is the commands.js file:
Cypress.Commands.add('loginRequest', function (tokenValue) {
return cy.request({
method: 'POST',
url: Cypress.config('baseUrl'),
followRedirect: true,
headers: {
'content-type': 'text/html; charset=UTF-8'
},
qs:{
_token: tokenValue,
username: 'your_username',
password:'your_password'
}
}).then(()=>{
return cy.request({
method: 'GET',
url: 'https://tenant-demo.somesitedev.net/dashboard',
followRedirect: false,
headers: {
'content-type': 'text/html; charset=UTF-8'
},
body:{
_token: tokenValue,
username: 'your_username',
password:'your_password'
}
})
})
});
I have a function that will return a token
var accessToken;
function TestToken(){
return cy.request({
method: 'POST',
url: "https://site/token",
headers: {
'Content-Type': 'application/json',
},
body: {
client_id: '1234',
client_secret: '1234',
audience: 'https://site/api/v1/',
grant_type: 'credentials'
}
}).then(response => {
return new Cypress.Promise((resolve, reject) => {
const rbody = (response.body);
var tokenPattern = "(?i)\"access_token\":\\s*\"([^\"]*)\"";
const authToken = rbody.access_token;
accessToken = authToken
cy.log(accessToken);
resolve(accessToken);
return accessToken;
})
});
I call that function in another cypress command, as I need to use the token in the authorization header
Cypress.Commands.add("ResetPwd", () => {
const authToken = TestToken();
cy.log(authToken);
cy.request({
method: 'POST',
url: "https://site/api/v2/users/1234",
headers: {
'Content-Type': 'application/json',
'authorization': 'Bearer '+authToken,
},
body: {
password: 'Test4321',
connection: 'DB',
}
});
});
When I execute the command, I don't see the token being used. Instead I see "authorization": "Bearer [object Object]" in the request.
In the TestToken funtion, I added cy.log(authToken);, to verify it was correctly grabbing the token. The cypress test failed saying
CypressError: cy.then() failed because you are mixing up async and
sync code.
but I could still see the correct token in the console.
Here is the cypress test I am trying to run
describe('Token Test', function() {
before(() => {
cy.ResetPwd();
})
it('Go to website', function() {
cy.visit('https://site/login')
});
});
functions is synchronous so in moment of call it the result will be equal Promise, promise is object and when you try to stringify object (by + operator) you get [object Object].
After some time promise will be resolved and value in authToken variable will be correct.
To fix it is suggest use Cypress.Promise like in example id cypress docs: https://docs.cypress.io/api/utilities/promise.html#Basic-Promise
I am assuming the TestToken() function is a promise and resolves asynchronously causing the authToken to be [ object Object ]
You could use async/await and the code should work fine.
Add async before the arrow function and use await const authToken = TestToken()
I solved this, after lots of work using cy.task:
cy.request({
method: 'POST',
url: '/where/you/retrieve/your/token',
body: {username: user, password: password},
failOnStatusCode: true
}).then((response) => {
cy.task('setToken', response.body);
});
then:
cy.task('getToken').then((token) => {
cy.request({
method: 'GET',
url: '/your/protected/endpoint/here',
headers: {
authorization: `Bearer ${token}`
},
failOnStatusCode: true
}).then((response) => {
expect(response.something).to.eq(something.else);
});
});
This is a simple Post request using Axios inside Vue:
import axios from 'axios'
export default {
name: 'HelloWorld',
props: {
msg: String
},
mounted () {
const code = 'test'
const url = 'http://localhost:3456/'
axios.post(url, code, { headers: {'Content-type': 'application/x-www-form-urlencoded', } }).then(this.successHandler).catch(this.errorHandler)
},
methods: {
successHandler (res) {
console.log(res.data)
},
errorHandler (error) {
console.log(error)
}
}
}
The Get method works fine. But Post stay as "Pending" on Network tab. I can confirm that there is a Post method on my webservice and it return something (tested on Postman).
UPDATE
Sending code as a param:
axios(url, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
params: {
code : 'test'
},
}).then(this.successHandler).catch(this.errorHandler)
WEBSERVICE
server.post('/', (req, res, next) => {
const { code } = req.params
const options = {
validate: 'soft',
cheerio: {},
juice: {},
beautify: {},
elements: []
}
heml(code, options).then(
({ html, metadata, errors }) => {
res.send({metadata, html, errors})
next()
})
})
I think there's issue with your axios request structure.
Try this:
const URL = *YOUR_URL*;
axios(URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
data: *YOUR_PAYLOAD*,
})
.then(response => response.data)
.catch(error => {
throw error;
});
If you're sending a query param:
axios(URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
params: {
code: 'your_string'
},
})
if it is path variable you can set your url:
const url = `http://localhost:3456/${code}`
Let me know if the issue still persists
I also was facing the same. Network call was pending all the time and Mitigated it by passing the response back from server.js(route file) e.g(res.json(1);) and it resolved the issue
I have this function in JS:
export let findUser = (user, pass) => fetch(baseURL+'/api/Login',{
method: 'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username:user,
password:pass,
})
})
.then((response) => response.json())
.then((res) => {
if(res.success === true){
return 'A';
}else{
alert(res.message);
}
}).
.done();
But when I call it in React like this :
var user = file.findUser(this.state.username,this.state.password);
I got undefined as content of variable user, How can I pass a value from the first function and get it in react native ?
I would suggest exporting the initial method call and handling the .then() and .done() within the area being exported to. For example:
I have this function in JS:
export let findUser = (user, pass) => fetch(baseURL+'/api/Login',{
method: 'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username:user,
password:pass,
})
})
using in another file
let user // assign user within response block
file.findUser(this.state.username, this.state.password)
.then((res) => { /* do what you want */ })
.then((res) => { /* do what you want */ })
.done()