Polly.js + selenium-webdriver: How to stub/intercept XHR requests - javascript

I'm running selenium tests for a react app, and I'm trying to stub my axios (XHR) requests. Ithink I'm close but seems like there's something missing. I'm running polly l - listening on localhost:3000 - and then my test looks like this:
import { Polly } from '#pollyjs/core'
import XHRAdapter from '#pollyjs/adapter-xhr'
import LocalStoragePersister from '#pollyjs/persister-local-storage';
import webdriver from 'selenium-webdriver'
const { By, Key, until } = webdriver
Polly.register(XHRAdapter)
Polly.register(LocalStoragePersister);
describe('Loggin in', () => {
const polly = new Polly('Sign In', {
adapters: ['xhr'],
persister: 'local-storage'
});
const { server } = polly;
polly.configure({
persisterOptions: {
'local-storage': {
key: '__pollyjs__'
}
}
});
server.get("http://localhost:3000/dashboard").passthrough()
server.get('http://localhost:3000/api/users/me').intercept((req, res) => {
res.status(200);
res.json({});
});
server.put('http://localhost:3000/api/users/login').intercept((req, res) => {
res.status(200);
res.json({});
});
it('renders correctly', async() => {
var chromeCapabilities = webdriver.Capabilities.chrome();
var chromeOptions = {
//'args': ['--headless']
'args': ['--auto-open-devtools-for-tabs']
};
chromeCapabilities.set('chromeOptions', chromeOptions);
const driver = new webdriver.Builder().withCapabilities(chromeCapabilities).build();
jasmine.Ajax.stubRequest('/dashboard').andReturn({
"status": 200
});
await driver.get('http://localhost:3000/dashboard')
await driver.getCurrentUrl().then((url) => {
expect(url).toEqual("http://localhost:3000/dashboard")
})
await polly.stop();
driver.quit()
})
})
So the idea here is that "/dashboard" should be passed through and not be intercepted at all, while the api requests (/api/users/meand /api/users/login) should be stubbed by polly. What happens is that when landing on /dashboard I get a 404 back and polly seem to not pass it through at all. Have I got it completely wrong here?
Cannot GET /dashboard

Related

Is there a reason why a promise will be undefined on Reactjs build but gets resolved on the localhost?

I have a react project setup with Redux and Axios. This is a function I am using to get data from an endpoint in my Redux actions:
export const getCSEfirstStageApplicants = () => async (dispatch) => {
try {
dispatch(LOADING());
const response = await axios.get(
`${baseUrl}/Franchisee/CSEFirstStageApplication`
);
if (response.status === 200) {
const { message, data } = response?.data || {};
return { message, data };
}
} catch (error) {
const { message } = error?.response?.data || {};
return message;
} finally {
dispatch(STOP_LOADING());
}
};
My component looks something like this:
import { useState, useEffect } from "react";
import {getCSEfirstStageApplicants} from "../../../redux/user/actions";
import { useDispatch } from "react-redux";
const MyComponent = () => {
const [cseApplicants, setCseApplicants] = useState([]);
const dispatch = useDispatch();
const getFirstStage = async () => {
const response = await dispatch(getCSEfirstStageApplicants());
if (response && response.data) {
console.log(response);
setCseApplicants(response.data);
return;
}
setCseApplicants([]);
};
useEffect(() => {
getFirstStage();
}, [dispatch]);
}
Apparently, this is working fine on my localhost. But when I build the app and push it to the server, it is giving an error on Chrome and Firefox and is working on Edge (browsers I have tested), indicating that response is undefined.
Chrome shows this error:
Firefox shows this error:
At first I thought it was the way the network call was made as preflight seemed to come after the xhr request. But checking Chrome showed that wasn't the error.
Another indication was an error that showed up as asyncgenerator error. I haven't been able to find a relation with this.
add properties to the empty object
const { message, data } = response?.data || {data:[], message:''};

Unable to display API data on React frontend

I'm trying to return data fetched from a private API and display it on a page. My frontend use React JS and my backend use node with Express and Axion. My code work up to the point of returning the data. I get my APi Key and fetch my data but the data is not transferred to my page (Quotes.js).
Backend
app.js
import express from "express";
import { getCase } from "./getCase.js";
const app = express();
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.get("/", function (req, res) {
console.log("app.js call getCase");
res.send(getCase());
//console.log(req);
});
//console.log(Quote.getQuote());
let port = process.env.PORT;
if (port == null || port == "") {
port = 5000;
}
app.listen(port, function () {
console.log(`Server started on port ${port}...`);
});
Backend getCase
import { getToken } from "./nsApiToken.js";
import axios from "axios";
let getData = "";
console.log("begin of getCase");
const getCase = async () => {
let tokenRes = await getToken();
const url =
"https://5156735-sb1.app.netsuite.com/app/site/hosting/restlet.nl?script=860&deploy=1&recordtype=supportcase&id=717986";
try {
const res = await axios.get(url, {
headers: {
Authorization: `Bearer ${tokenRes.data.access_token}`,
},
});
return res;
} catch (error) {
return error;
}
};
export { getCase };
Frontend App.js
import logo from "./logo.svg";
import "./App.css";
import Quotes from "./Quotes.js";
function App() {
return (
<div className="App">
<header className="App-header">
<Quotes />
</header>
</div>
);
}
export default App;
Frontend Quotes.js
import React, { useState, useEffect } from "react";
import axios from "axios";
const Quotes = async () => {
const [text, setText] = useState([]);
const [author, setAuthor] = useState("");
const getQuote = await axios
.get("http://localhost:5000", {
crossdomain: true,
})
.then((res) => res.data)
.then((data) => {
setText({
data: data,
});
console.log("res: ", text);
});
return (
<div>
<button onClick={getQuote}>Generate Quote</button>
<h1>{text}</h1>
<h3>{author}</h3>
</div>
);
};
export default Quotes;
Process:
When I run my process the front execute and call Quotes.js in the axios get process.
app.js then route to home ('/') and call getCase via the app.get.
The getCase process execute get the API token and add it in the headers Authorization. The process initiate the call and fetch the data (if I console.log(res.data.fields.phone) or console.log(res.data.id) I see the correct data.
In my Quotes.js I want to display the data but res.data is empty, yet I get back status 200.
I've been trying to understand why it is not passing the data from the backend to the frontend.
There are several problems and some improvements to be made.
Backend
Problem - You are sending the entire AxiosResponse in the response from your Express app
Just send the data
const getCase = async () =>
(
await axios.get(
"https://5156735-sb1.app.netsuite.com/app/site/hosting/restlet.nl",
{
params: {
script: 860,
deploy: 1,
recordtype: "supportcase",
id: 717986,
},
headers: {
Authorization: `Bearer ${(await getToken()).data.access_token}`,
},
}
)
).data; // Return the data, not the whole response
Problem - getCase() is async
You need to await the result
app.get("/", async (req, res, next) => {
try {
res.json(await getCase());
} catch (err) {
next(err); // send the error to the Express error handler
}
});
Improvement - Creating your own CORS middleware is a waste of time
By the time you create a comprehensive CORS middleware, it will look exactly the same as the standard one so just use that
import express from "express";
import cors from "cors";
const app = express();
express.use(cors());
Frontend
Problem - React function components cannot be async
Function components must return a valid JSX node. Remove async from Quotes
Problem - getQuote should be a function
In order to trigger getQuote by button click, it needs to be a function
// if text is an object, initialise it as one
const [text, setText] = useState({});
const getQuotes = async () => {
try {
// there is no "crossdomain" Axios option
const { data } = await axios.get("http://localhost:5000");
setText({ data });
} catch (err) {
console.error(err.toJSON());
}
};
Problem - the text state is an object
JSX cannot render plain objects, you instead need to reference properties that can be rendered.
<h1>{text.data?.some?.property}</h1>
No idea what your response object looks like so this is just generic advice
The reason why this is not working is for two reasons. Firstly, res.data is not an asynchronous function. And since you are doing await, you can just get data. Secondly, you need to make your API calls and setState in the useEffect hook or else it would just end up in an infinite rerender situation. You just have to do the following and it should work:
useEffect(() => {
const fetchData = async () => {
const {data} = await axios
.get('http://localhost:5000', {
crossdomain: true
})
setText(data)
}
fetchData()
}, [])

I can't download a file with nodejs backend and react frontend

I am trying to download a requested file from the frontend to a backend server with nodejs. To do it in react I use axios and in nodejs I am using express. The problem is that with my implementation I get the following error:
Error [ERR_STREAM_CANNOT_PIPE]: Cannot pipe, not readable
at new NodeError (node:internal/errors:371:5)
at ServerResponse.pipe (node:_http_outgoing:987:22)
at file:///home/marc/Disco/Projects/GymApp/server/routes/trainer.js:249:9
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Emitted 'error' event on ServerResponse instance at:
at ServerResponse.pipe (node:_http_outgoing:987:8)
at file:///home/marc/Disco/Projects/GymApp/server/routes/trainer.js:249:9
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: 'ERR_STREAM_CANNOT_PIPE'
Here is the axios request:
const downloadTraining = async (id) => {
const JWT = new ClassJWT();
const axiosReq = axios.create();
await JWT.checkJWT();
axiosReq
.post(`${serverPath}/download-training`, {
trainer_id: await JWT.getId(),
training_id: id,
token: JWT.getToken(),
})
.then((res) => {
console.log(res);
})
.catch((err) => console.log(err));
}
Here I don't know what to do for the browser to download the file, if anyone know it, let me know.
Here is the nodejs code with express that gives me the error that I mentioned above:
import express from "express";
import { verifyJWT } from "../services/tokens/verifyJWT.js";
import Training from "../models/Training.js";
import fs from "fs";
const path = "/home/marc/Disco/Projects/AtlasFitness/";
const dirname = "uploads/trainings/";
routerTrainer.post("/download-training", verifyJWT, async (req, res) => {
const { trainer_id, training_id } = req.body;
let training = await Training.findOne({
where: { id: training_id, trainer_id },
});
if (training) {
const filePath = fs.createWriteStream(`${path}${dirname}${training.file_id}`);
res.pipe(filePath);
filePath.on('finish',() => {
filePath.close();
console.log('Download Completed');
})
}
})
Here is when I get the error, if anyone know how to fix it to get the file downloaded to the user's computer, please let me know it.
It should be a read stream on the API, not a write stream.
const filePath = fs.createReadStream(`${path}${dirname}${training.file_id}`);
res.pipe(filePath);
filePath.on('finish',() => {
filePath.close();
console.log('Download Completed');
})

Error occurred prerendering page in Next JS [duplicate]

This question already has an answer here:
Fetch error when building Next.js static website in production
(1 answer)
Closed last year.
I created an API in next JS (in the pages/api folder) and I used it on a page in the pages folder.
When I run on the localhost (development stage), the API can be called correctly. But when I deploy to Vercel there is an error during build.
This is my code when i call the API which is in the pages/api folder
export const getStaticProps = async () => {
const baseUrlDribble = 'https://api.dribbble.com/v2';
const baseUrl = process.env.NODE_ENV === 'production' ?
'https://jovanka-samudra.vercel.app/api' : 'http://localhost:3000/api';
const resShots = await fetch(`${baseUrlDribble}/user/shots?access_token=${process.env.TOKEN_DRIBBLE}&page=1&per_page=9`);
const shots = await resShots.json();
const resResult = await fetch(`${baseUrl}/projects`);
const result = await resResult.json();
const projects = result.data.projects;
return {
props: {
shots,
projects,
},
revalidate: 1,
}
}
This is the API code to retrieve data from database (pages/api/projects folder)
import ProjectService from "#services/ProjectService";
import connectDB from "#utils/connectDB";
import projectValidator from "#validators/project";
import ClientError from '#exceptions/ClientError';
const handler = async (req, res) => {
const projectService = new ProjectService();
if (req.method === 'GET') {
try {
const projects = await projectService.getProjects();
return res.status(200).json({
success: true,
length: projects.length,
data: {
projects
}
});
} catch (error) {
return res.status(500).json({
success: false,
message: error.message,
});
}
} else if (req.method === 'POST') {
...
}
return res.status(404).json({
success: false,
message: 'Method not alowed'
});
}
export default connectDB(handler);
services/ProjectService folder
import InvariantError from '#exceptions/InvariantError';
import NotFoundError from '#exceptions/NotFoundError';
import Project from '#models/Project';
class ProjectService {
async getProjects() {
const projects = await Project.find().sort({ 'createdAt': -1 });
return projects;
}
...
}
export default ProjectService;
You should not fetch an internal API route from getStaticProps — instead, you can write the fetch code in API route directly in getStaticProps.
https://nextjs.org/docs/basic-features/data-fetching/get-static-props#write-server-side-code-directly

Porblem with Axios request in React

I am trying to launch a post Axios request from my front to my back using React framework. When I use my localhost server its works but I use Heroku address, I have an error message (400 bad request) in my console.
I tried to launch other get Axios requests with heroku and it works. So I am wondering that the problem I have is related to Post Axios requests.
I will appreciate your comments
please find below my code (front react):
import React from "react";
import axios from "axios";
const Questions = () => {
const fetchData = async () => {
const response = await axios.post(
"https://formnest-back-certification.herokuapp.com/form/create",
{
title: "nouveau formulaire",
}
);
console.log(response.data);
};
fetchData();
return (
<>
<div>Hello form</div>
</>
);
};
export default Questions;
Here is my code in the back React:
router.post("/form/create", async (req, res) => {
try {
/* const titleForm = await Form.findOne({ title: req.fields.title });
console.log(titleForm);
if (titleForm) {
return res.status(400).json({ error: "title already used" });
} else { */
if (req.fields.title) {
const newForm = new Form({
title: req.fields.title,
/* questions: req.fields.questions,
answers: req.fields.answers, */
});
// Sauvegarde du formulaire
await newForm.save();
return res.json(newForm);
} else {
return res.status(400).json({ error: "Missing parameters" });
}
} catch (e) {
return res.status(400).json({ error: e.message });
}
/* console.log(req.fields); */
/*
res.json({ message: "form created" }); */
});
If you are using express framework for the POST request, you need to using body-parser module then using req.body to retrieve the request data.
req.fields is when you are using express-formidable module.

Categories