cypress request PATCH call for local stub server fails - automation

I have a local stub server which has a PATCH request. When I call this local endpoint inside cypress, it fails.
My cypress code
Cypress.Commands.add('callLocalAPI', (id: string = '1') => {
const options = {
method: 'PATCH',
url: `${Cypress.env().baseUrl}test/api`,
// failOnStatusCode: false,
retryOnStatusCodeFailure: true,
log: true,
body: {
id,
},
}
// we need cy to visit the current URL so it grabs cookie
// for our request
cy.visit('/')
cy.request(options).then((response) => {
if (!String(response.body.id)) {
console.error(response)
throw Error(`Fail to get response with ${id}`)
}
})
})
then calling this custom cypress command
cy.callLocalAPI('2')
When I access this endpoint using postman (http://localhost:8882/test/api), I get the expected response with a status code of 200 so there is no issues with the mock server.
But when I run the cypress tests, I always get a 404.
Status: 404 - Not Found
Headers: {
"server": "stubby/5.0.0 node/v12.19.0 (darwin x64)",
"date": "Fri, 03 Sep 2021 03:36:49 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
}

Try
const options = {
method: 'PATCH',
url: 'test/api',
...
From Cypress docs - request
If you make a cy.request() after visiting a page, Cypress assumes the url used for the cy.visit() is the host.
cy.visit('http://localhost:8080/app')
cy.request('users/1.json') // url is http://localhost:8080/users/1.json
It may simply be that this line is missing a path separator
url: `${Cypress.env().baseUrl}test/api`
Cypress.env().baseUrl
Note that the value for this string is
taken from the file cypress.env.json (not cypress.json)
{
"baseUrl": "http://localhost:8882/"
}
or overridden in the command line
cypress open --env baseUrl=http://localhost:8882/

Related

Axios CORS not working on chrome deployed site

I have the following method in a VueJS application:
const downloadImageBase64 = async imageUrl => {
try {
var result = await axios({
method: "get",
url: imageUrl,
responseType: 'blob',
crossdomain: true
});
return blobToBase64(result.data);
}
catch (err) {
console.log("err: ", err);
return "";
}
};
I am downloading images and returning them as a base64 strings because I'm embedding them into PDF's that I'm creating using JSPDF. The images themselves are hosted in AWS S3. I have the CORS policy set up in the appropriate S3 bucket:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"https://mydomain.co.za"
"http://localhost:8082"
],
"ExposeHeaders": [],
"MaxAgeSeconds": 3000
}
]
When running the app on my localhost, the image download succeeds with both FireFox and Chrome:
However, the moment I deploy the app to my staging environment, the download starts to fail with CORS issues, but only on Chrome. Looking at the request headers, no CORS info is even being sent:
I don't know if there's a preflight that Chrome is not showing in the network traffic, but the console gives me the following error:
Access to XMLHttpRequest at 'https://my-bucket.s3-eu-west-1.amazonaws.com/my-image-path.png' from origin 'https://mydomain.co.za' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
It turns out the issue is that I display the images on the webpage where the download PDF button is placed, which means that chrome caches these images and when attempting to download the images for the PDF, chrome is returning the cached images without the CORS headers. I more or less got the answer from here:
https://www.hacksoft.io/blog/handle-images-cors-error-in-chrome
So the solution is to append a throw-away get parameter to the URL when downloading for the PDF:
const downloadImageBase64 = async imageUrl => {
try {
var result = await axios({
method: "get",
url: `${imageUrl}?not-from-cache-please`,
responseType: 'blob',
crossdomain: true
});
return blobToBase64(result.data);
}
catch (err) {
console.log("err: ", err);
return "";
}
};
Note the:
url: `${imageUrl}?not-from-cache-please`

Website login automation without XHR request

Background: I'm trying to automate local ISP login using simple request in python (without selenium, that's last resort as I'm trying to learn other ways too).
Upon inspecting website, submit button calls the validateForm() function.
function validateForm(){
var input=true;
var uname = "?"+document.login.Username.value+"+/#";
var pwd = "?"+document.login.Password.value+"+/#";
document.login.LoginName.value=encodeURIComponent(uname);
document.login.LoginPassword.value=encodeURIComponent(pwd);
if (input==true&&document.login.checker.checked)
toMem(this);
}
function toMem(a) {
newCookie('theName', document.login.Username.value); // add a new cookie as shown at left for every
newCookie('theEmail', document.login.Password.value); // field you wish to have the script remember
}
function newCookie(Username,value,days) {
var days = 30; // the number at the left reflects the number of days for the cookie to last
// modify it according to your needs
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString(); }
else var expires = "";
document.cookie = Username+"="+value+expires+"; path=/";
}
No where it is sending any request.
The website doesn't make any XHR request. I'm not able to grasp how they are making the login work. I found one request from 'other' tab of network (chrome dev tools). From where it is generating this request!!!
fetch("http://ip:port/Sristi3/SRISTI/loginUI.do2", {
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"accept-language": "en-US,en;q=0.9,bn;q=0.8",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"pragma": "no-cache",
"upgrade-insecure-requests": "1"
},
"referrer": "http://ip:port/Sristi3/SRISTI/Login.jsp?",
"referrerPolicy": "no-referrer-when-downgrade",
"body": "Username=username&Password=password&LoginName=encodedusername&LoginPassword=encodedpass",
"method": "POST",
"mode": "cors",
"credentials": "include"
});
I tried to simply paste the request in console but this also does not make the login. Returned a promise with [[PromiseStatus]]: "rejected" and [[PromiseValue]]: TypeError: Failed to fetch, message: "Failed to fetch", stack: "TypeError: Failed to fetch". What and where to look for? Any help?

Unable to authenticate a user using #hapi/cookie 19.x.x

I've recently upgraded my project to use hapi 19.x.x along with that I have updated the project to use #hapi/cookie as opposed to the deprecated hap-auth-cookie however after successful authentication my application constantly tries to reauthenticate even after setting a session cookie with request.cookieAuth.set({ id : id})
When the application is redirected to the 'restricted page' using the redirectTo: property on the .auth.strategy('admin', 'cookie', {}) object.
I noticed that the state on the incoming request is {} empty when it shouldn't be
node -v // 12.16.2
Google Chrome
Version 80.0.3987.163 (Official Build) (64-bit)
package.json {
"dependencies": {
"#hapi/catbox-redis": "5.0.5",
"#hapi/cookie": "11.0.1",
"#hapi/h2o2": "9.0.1",
"#hapi/hapi": "19.1.1",
"#hapi/inert": "6.0.1",
"#hapi/joi": "17.1.1",
"#hapi/scooter": "6.0.0",
"#hapi/wreck": "17.0.0",
}
server.auth.strategy('admin', 'cookie', {
cookie: {
name: Server.cookieName,
password: auth_cookie_password,
isSecure: false,
ttl: Server.cacheCookieTtlMs
},
appendNext: true,
redirectTo: outboundUrl,
validateFunc: async (request: any, session: any) => {
// blah blah
}
{
method: ['GET', 'POST'],
path: '/login',
options: {
auth: false,
security: true
},
handler: async (request: any, h) => {
try {
const tokenSet = await authCallback();
const session = {
id: tokenSet.id,
}
request.cookieAuth.set(session);
const returnScript = `<script type="application/javascript" >(function() { setTimeout(function() {window.location = "http://localhost:3000"})})()</script>`;
return h.response(returnScript)
} catch (e) {
return h.response('Internal server error').code(500)
}
}
}
any help would be appreciated.
you have to set the cookie path to /
Cookies are only sent to the server when the URL of the request starts with the value of the cookie’s path. When you omit path, the default is the URL of the request that received the response with the Set-Cookie header. So, let’s say you omit path and your cookie is set on a URL like https://example.com/login (which is very common), then the cookie will only be sent on requests for subpaths like https://example.com/login/foo, which is almost never what you want.

How to handler server redirect from axios

I have a vue web app that uses axios to communicate with an API. The authentication is handled by the server, and not by my app. That is, the server ensures that the user cannot see the app before they have authenticated.
Of course, after some time the user's authentication token expires and my app only notices this when it fires off a get/post request to the API. When this happens the axios request returns a redirect to a login page that, when printed to the console, looks something like this:
config: Object { url: "https://...url for my request...",
method: "get", baseURL: "...base url for api", … }
data: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<HTML>\n<HEAD>\n<TITLE>Need Authentication</TITLE>\n<link rel=\"stylesheet\" href=\"/Steely.css\" type=\"text/css\">\n</HEAD>\n<BODY>....</BODY>\n</HTML>\n"
headers: Object {
connection: "Keep-Alive",
"content-encoding": "gzip", "content-length": "1686", …
}
request: XMLHttpRequest {
readyState: 4, timeout: 0, withCredentials: false, …
}
status: 200
statusText: "OK"
<prototype>: Object { … }
app~d0ae3f07.235327a9.js:1:97292
What is the best way to redirect the user to this login page and then resume my original request? At the moment I am not even succeeding in recognising this. My axios code tries, and fails, to recognise when this happens and then redirect to user a vue component that has a login page. The relevant part of code looks like this:
export default new class MyAPI {
constructor() {
this.axios = axios.create({
headers: {
'Accept': 'application/json',
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
},
baseURL: `https://.../api`,
});
}
// send a get request to the API
GET(command) {
return new Promise((resolve, reject) => {
this.axios.get(command)
.then((response) => {
if (response && response.status === 200) {
if ( response.data && typeof response.data == 'string' && response.data.includes('Require authentication') ) {
store.dispatch('authenticate', this.baseURL+'/'+command).then( (resp) => resolve(resp.data) )
} else {
resolve(response.data);
}
} else {
reject(response.data);
}
})
.catch((err) => { reject('Internal error'+err); });
});
}
}
This results in the dreaded
Internal errorTypeError: e(...) is undefined
error, although this error is almost certainly triggered further down the code since I not recognising the login authentication request.
Is anyone able to recommend how best to recognise and process the login request?

React, Axios issue: Response for preflight does not have HTTP ok status ( 404 not found )

I've been trying using axios with basic auth but it always returns not found.
Here is my code
const ROOT_URL='http://localhost/b2b_ecom/b2b-api/index.php/api/';
export function login () {
return function(dispatch)
{
const api = axios.create({
mode: 'no-cors',
credentials:'include',
redirect: 'follow',
auth: {
username: 'mouad#b2b.dz',
password: '123456'
},
headers: {
'Content-Type': 'application/json',
}
});
api.post(`${ROOT_URL}site/login `).then(function(response)
{
dispatch({LOGIN,payload:response.data});
return true;
}).catch(function(error)
{
return error;
});
} ;
}
And here it is the error I got:
OPTIONS http://localhost/b2b_ecom/b2b-api/index.php/api/site/login 404 (Not Found)
Failed to load http://localhost/b2b_ecom/b2b-api/index.php/api/site/login: Response for preflight does not have HTTP ok status.
Screenshot
I think browser is adding access control header to request.
Check the following things
1) When you hit from postman or other such api clients this api should be working properly. (even curl is fine)
2) Try adding Access-Control-Allow-Origin as * for this request on server and see if it works.