I have a problem with data stubbing in Cypress 6. I am trying to implement the exchange of real data from the server to custom data. I read the docs and came to the conclusion that
describe("test", () => {
it("intercept", () => {
cy.intercept("http://localhost:3000/spoons", (req) => {
req.reply((res) => {
let { body } = res;
body.newProperty = "new";
console.log(res.body);
return body;
});
});
});
});
will be the solution, however... body in networking for request http://localhost:3000/spoons returns to me
{
"sizes": [
"huge",
"small"
],
"colors": [
"yello",
"brown"
],
"build": {
"back": true,
"front": true
}
}
but in the console.log as it shows what res.body has, it gets an empty console.log as if it had nothing res.body in it.
Edit #1
About internal "server" I made just simple express server with a website which make fetch request to have easy another request in "Networking". It was made just as a battlefield to train intercept and other stuff. There is the only endpoint to this /spoons
server.js
const express = require("express");
const app = express();
const port = 3000;
const path = require("path");
const obj = {
sizes: ["huge", "small"],
colors: ["yello", "brown"],
build: {
back: true,
front: true,
},
};
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname + "/index.html"));
});
app.get("/spoons", (req, res) => {
res.json(obj);
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
console.log(fetch("http://localhost:3000/spoons"));
</script>
</html>
It works for intercepting external network requests,
/// <reference types="#cypress/fiddle" />
const test = {
html: `
<script>
fetch('https://jsonplaceholder.typicode.com/todos/1')
</script>
`,
test: `
cy.intercept('https://jsonplaceholder.typicode.com/todos/1', req => {
req.reply((res) => {
let { body } = res;
body.newProperty = "new";
console.log(res.body);
return body;
});
})
`
}
it('test', () => {
cy.runExample(test)
})
This logs
{
completed: false,
id: 1,
newProperty: "new", // added by intercept
title: "delectus aut autem",
userId: 1
}
Can you explain the api server and client ports in more detail?
I set up your server, and found it works ok.
The only thing I changed was to add a no-store header to the server response (stops browser seeing status code '304').
Without it every second refresh of the Cypress test cy.intercept() did not trigger. That may actually be fixable in the test by adding a full route matcher to cy.intercept() instead of just the url.
app.use((req, res, next) => {
res.set('Cache-Control', 'no-store')
next()
})
app.get("/", (req, res) => {...
I also modified the script in the app to console.log in .then(), otherwise you just get the promise object.
<script>
fetch('http://localhost:3000/spoons')
.then(res => res.json())
.then(res => console.log('app', res))
</script>
This is the spec I used.
it('test', () => {
cy.intercept('http://localhost:3000/spoons', req => {
req.reply((res) => {
let { body } = res;
body.newProperty = "new";
console.log('intercept', res.body);
return body;
});
})
cy.visit('../app/intercept-mod-response-local-server-2.html')
})
Related
I am creating OAuth2 for my application by which the people who are redirected to the server by clickking it will get the verified role. Can somebody please help me on how i can add it in my script. Right now I am using the script given below:
const express = require('express');
const { port } = require('./config.json');
const app = express();
app.get('/', (request, response) => {
console.log(`The access code is: ${request.query.code}`)
;
return response.sendFile('index.html', { root: '.' });
});
app.listen(port, () => console.log(`App listening at http://localhost:${port}`));
and from the index file they get redirected to the server here's the index.html script:
<script>
window.location.href = "https://discord.gg/DhsYQ3u4jj";
</script>
<div id="info">Congrats! You have been successfully connected to Discord.</div>
<a id="login" style="display: none;" href="https://discord.gg/jkBJarBY">Click here to Join Akudo's official Discord!</a>
<script>
window.onload = () => {
const fragment = new URLSearchParams(window.location.hash.slice(1));
const [accessToken, tokenType] = [fragment.get('access_token'), fragment.get('token_type')];
if (!accessToken) {
return (document.getElementById('login').style.display = 'block');
}
fetch('https://discord.com/api/users/#me', {
headers: {
authorization: `${tokenType} ${accessToken}`,
},
})
.then(result => result.json())
.then(response => {
const { username, discriminator } = response;
document.getElementById('info').innerText += ` ${username}#${discriminator}`;
})
.catch(console.error);
};
</script>
When deploying a twitter streaming app which is working well on my local environment, to a live webserver, I'm getting a 404 error related to socket.io. I saw that there a numerous similar questions here already but did not find an answer solving the problem I'm facing.
Problem description:
Once I start server.js, it correctly logs 'Listening on Port 3000' to the console (terminal)
However, the message "Client connected..." is not triggered
In the browser console, I'm seeing the error message "GET https://exampledomain.com/socket.io/?EIO................(etc) - 404 - XHR failed loading"
I have already tried the following changes without success, amongst other things:
Changed the server.js code from const http = require('http') to const https = require('https')
Changed the port from 3000 to others to rule out a certain port # is already in use elsewhere, e.g. 8001 or 3333
The full server code (in public_html/server/server.js):
const http = require('http')
const path = require('path')
const express = require('express')
const socketIo = require('socket.io')
const needle = require('needle')
const config = require('dotenv').config()
const TWITTER_BEARER_TOKEN = 'xxxxxx'
const PORT = process.env.PORT || 3000
const app = express()
const server = http.createServer(app)
const io = socketIo(server)
console.log(path.resolve(__dirname, '../', 'public_html/client', 'index.html'))
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, '../', 'public_html/client', 'index.html'))
// /usr/www/users/antick/public_html/client/index.html
})
const rulesURL = 'https://api.twitter.com/2/tweets/search/stream/rules'
const streamURL = 'https://api.twitter.com/2/tweets/search/stream?tweet.fields=public_metrics&expansions=author_id,attachments.media_keys&media.fields=duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width&user.fields=profile_image_url'
const rules = [{ value: 'corruption' }]
// Get stream rules
async function getRules() {
const response = await needle('get', rulesURL, {
headers: {
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
return response.body
}
// Set stream rules
async function setRules() {
const data = {
add: rules
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
return response.body
}
// Delete stream rules
async function deleteRules(rules) {
if (!Array.isArray(rules.data)) {
return null
}
const ids = rules.data.map((rule) => rule.id)
const data = {
delete: {
ids: ids
}
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
return response.body
}
function streamTweets(socket) {
const stream = needle.get(streamURL, {
headers: {
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
stream.on('data', (data) => {
try {
const json = JSON.parse(data)
console.log(json)
socket.emit('tweet', json)
} catch (error) {}
})
}
io.on('connection', async () => {
console.log('Client connected...')
let currentRules
try {
// Get all stream rules
currentRules = await getRules()
// Delete all stream rules
await deleteRules(currentRules)
// Set rules based on array above (Rules)
await setRules()
} catch (error) {
console.error(error)
process.exit(1)
}
streamTweets(io)
})
server.listen(PORT, () => console.log(`Listening on Port ${PORT}`))
My client code - excerpt only (in public_html/client/index.html):
<div class="container">
<div id="tweetStream"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.1.2/socket.io.js" integrity="sha512-iZIBSs+gDyTH0ZhUem9eQ1t4DcEn2B9lHxfRMeGQhyNdSUz+rb+5A3ummX6DQTOIs1XK0gOteOg/LPtSo9VJ+w==" crossorigin="anonymous" referrerpolicy="no-referrer">
</script>
<script>
const tweetStream = document.getElementById('tweetStream')
const socket = io()
//const socket = io.connect('https://www.exampledomain.com:3000/');
const tweets = []
socket.on('connect', () => {
console.log('Connected to server...')
})
socket.on('tweet', (tweet) => {
// (code continues here)
My suspicion is that is has to do something with the paths used in these two locations:
in server/server.js:
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, '../', 'public_html/client', 'index.html'))
// resolves to: /usr/www/users/antick/public_html/client/index.html
})
in client/index.html: const socket = io() //
What else could possibly cause the error described above? I am grateful for any help. Thanks!
With help from a pro developer I was finally able to fix the problem so I would like to post the solution.
The two main points were:
Open Port # 3000 to any IPs (as it is unknown from which IP address a client would access the site)
Install pm2 in addition to node in order to constantly stream the tweets
The full resulting code looks as follows:
A) Server (index.js):
const http = require('http')
const path = require('path')
const express = require('express')
const socketIo = require('socket.io')
const needle = require('needle')
const config = require('dotenv').config()
const TOKEN = process.env.TWITTER_BEARER_TOKEN
const PORT = process.env.PORT || 3000
const app = express()
const server = http.createServer(app)
const io = socketIo(server)
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, '../', 'client', 'index.html'))
})
const rulesURL = 'https://api.twitter.com/2/tweets/search/stream/rules'
const streamURL = 'https://api.twitter.com/2/tweets/search/stream?tweet.fields=public_metrics&expansions=author_id,attachments.media_keys&media.fields=duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width&user.fields=profile_image_url'
const rules = [{ value: 'searchterm' }]
// Get stream rules
async function getRules() {
const response = await needle('get', rulesURL, {
headers: {
Authorization: `Bearer ${TOKEN}`
}
})
return response.body
}
// Set stream rules
async function setRules() {
const data = {
add: rules
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TOKEN}`
}
})
return response.body
}
// Delete stream rules
async function deleteRules(rules) {
if(!Array.isArray(rules.data)) {
return null
}
const ids = rules.data.map((rule) => rule.id)
const data = {
delete: {
ids: ids
}
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TOKEN}`
}
})
return response.body
}
function streamTweets (socket) {
const stream = needle.get(streamURL, {
headers: {
Authorization: `Bearer ${TOKEN}`
}
})
stream.on('data', (data) => {
try {
const json = JSON.parse(data)
console.log(json)
console.log(json.includes.media[0])
socket.emit('tweet', json)
} catch (error) {}
})
}
io.on('connection', async () => {
console.log('Client connected...')
let currentRules
try {
// Get all stream rules
currentRules = await getRules()
// Delete all stream rules
await deleteRules(currentRules)
// Set rules based on array above (Rules)
await setRules()
} catch (error) {
console.error(error)
process.exit(1)
}
streamTweets(io)
})
server.listen(PORT, () => console.log(`Listening on Port ${PORT}`))
B) Client (index.html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="
crossorigin="anonymous"
/>
<title>Real-Time Tweet Stream</title>
</head>
<body>
<nav class="navbar navbar-dark bg-dark">
<div class="container">
Real-Time Tweet Stream
</div>
</nav>
<div class="container">
<div id="tweetStream"></div>
</div>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js"
integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ=="
crossorigin="anonymous"
></script>
<script>
const tweetStream = document.getElementById('tweetStream')
const socket = io('IP.IP.IP.IP:3000' , { transports : ['websocket'] } ) // webserver IP address
const tweets = []
socket.on('connect', () => {
console.log('Connected to server...')
})
socket.on('tweet', (tweet) => {
// console.log(tweet)
const tweetData = {
id: tweet.data.id,
text: tweet.data.text,
username: `#${tweet.includes.users[0].username}`,
}
const tweetEl = document.createElement('div')
tweetEl.className = 'card my-4'
tweetEl.innerHTML = `
<div class="card-body">
<h5 class="card-title">${tweetData.text}</h5>
<h6 class="card-subtitle mb-2 text-muted">${tweetData.username}</h6>
<a class="btn btn-primary mt-3" href="https://twitter.com/${tweetData.username}/status/${tweetData.id}">
<i class="fab fa-twitter"></i> Go To Tweet
</a>
</div>
`
tweetStream.appendChild(tweetEl)
})
</script>
</body>
</html>
I am trying to build a reverse-proxy server where the url has an id (?id=1) and the proxy server redirects to port 8000 + id!
So it works when i go to the right port directly, but when I use the proxy the browser-tab loads endlessly.
It also works with GET-Request, but POST-Request don't work!
This is my reversed-proxy:
const express = require(`express`);
const proxy = require(`http-proxy`);
const ps = proxy.createProxyServer();
const app = express();
app.listen(8000);
app.all(`*`, (req, res) => {
if (req.query.id) {
try { const id = parseInt(req.query.id);
ps.web(req, res, { target: `${req.protocol}://${req.hostname}:${8000+id}` });
} catch (err) { res.redirect(redirectUrl); }
} else { res.redirect(redirectUrl); }
});
ps.on(`error`, (err, req, res) => {
res.redirect(redirectUrl);
});
This is my website running on port 8001:
app.get(`*`, (req, res) => {
res.render(`index`, {
link: `?id=1`,
name: `name`,
value: `value`,
text: `text`,
});
});
app.post(`*`, (req, res) => {
res.render(`index`, {
link: `?id=1`,
name: `name`,
value: `value`,
text: `text`,
});
});
And this is my html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<form action={{link}} method="POST">
<button name={{name}} value={{value}}>
<h4> {{text}} </h4>
</button>
</form>
</body>
</html>
By the way i am also using express-handlebars so the {{}} in the html is for that!
ty for any ideas :)
So whats happening is I have a reactjs project that has react router. So when I try and hit /dashboard/stream it's getting the index.html off the server but then the css and js are getting 301 errors and it's not displaying anything.
express server
const express = require('express');
const {
createServer
} = require('http');
const io = require('socket.io');
const haiku = require('./haiku');
const app = express();
const server = createServer(app);
const userIds = {};
const noop = () => {};
app.use('/*', express.static(`${process.cwd()}/../client`));
/**
* Random ID until the ID is not in use
*/
function randomID(callback) {
const id = haiku();
if (id in userIds) setTimeout(() => haiku(callback), 5);
else callback(id);
}
/**
* Send data to friend
*/
function sendTo(to, done, fail) {
const receiver = userIds[to];
if (receiver) {
const next = typeof done === 'function' ? done : noop;
next(receiver);
} else {
const next = typeof fail === 'function' ? fail : noop;
next();
}
}
/**
* Initialize when a connection is made
* #param {SocketIO.Socket} socket
*/
function initSocket(socket) {
let id;
socket
.on('init', () => {
randomID((_id) => {
id = _id;
userIds[id] = socket;
socket.emit('init', {
id
});
});
})
.on('request', (data) => {
sendTo(data.to, to => to.emit('request', {
from: id
}));
})
.on('call', (data) => {
sendTo(
data.to,
to => to.emit('call', { ...data,
from: id
}),
() => socket.emit('failed')
);
})
.on('end', (data) => {
sendTo(data.to, to => to.emit('end'));
})
.on('disconnect', () => {
delete userIds[id];
console.log(id, 'disconnected');
});
return socket;
}
module.exports.run = (config) => {
server.listen(config.PORT);
console.log(`Server is listening at :${config.PORT}`);
io.listen(server, {
log: true
})
.on('connection', initSocket);
};
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<link href="/dist/css/app.min.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="/dist/js/app.min.js"></script>
</body>
</html>
how come my index.html is loaded but then the js and css isnt.
folder structure is this:
server
...
client
dist
css
js
index.html
...
To me I can't see if it's loading that index.html file how it can't load the css and js that are linked to it.
The problem is that you are using absolute path for the static files because they start with a / so if the url is /dashboard/stream then it will tries to load the css and js file from /dashboard/dist/....
To fix it remove the / from the beginning of the path to have a relative path.
<link href="dist/css/app.min.css" rel="stylesheet">
and
<script type="text/javascript" src="dist/js/app.min.js"></script>
This does the trick with Angular so why not with React considering that you are using front-end routing:
Use an absolute path in your server.js file:
app.use('/public', express.static(path.join(__dirname, '../client/dist')));
Serve your front-end routes in your server.js file:
app.get('*', function(req, res, next) {
res.sendFile("../client/index.html", { root: __dirname });
});
Now you should be able to access all the files inside the dist directory.
f.e: <script type="text/javascript" src="./public/js/app.min.js"></script>
Is it possible to "listen" an input text field at nodejs ?
I want to use a search input on my html page and i want to listen "live" any value that user types. Not to take the final value with a submit button and body parser.
I try to add an event listener after select my html input, but my selector is undefined.
here is my server.js file
// 3rd part modules
const express = require('express')
const hbs = require('hbs')
const fs = require('fs')
const moment = require('moment')
// App modules
const userData = require('./fetch')
// App basic configs
const port = process.env.PORT || 3000
const app = express()
//Log when someone is on app
app.use((req, res, next) => {
const now = moment().format("D MMM YYYY, HH:mm")
const clientIp = req.ip
const log = `${now}: from ${clientIp}`
fs.appendFile('server.log', `${log}\n`, (err) => {
if (err) throw err
})
next()
})
// Maintenance mode
// app.use((req, res, next) => {
// res.render('maintenance.hbs', {
// pageTitle: 'Maintenace mode'
// })
// })
// Express middleware to store public files & static pages
app.use(express.static(`${__dirname}/public`))
// View engine Handlebars
app.set('view engine', 'hbs')
// Use partials for header and footer
hbs.registerPartials(`${__dirname}/views/partials`)
// Pass custom functions everywhere
hbs.registerHelper('getCurrentYear', () => {
return new Date().getFullYear()
});
app.get('/', (req, res) => {
res.render('home-page.hbs', {
welcomeMessage: 'Welcome to home page',
pageTitle: 'Home page',
location: userData.location,
currentTemp: userData.currentTemp,
feelTemp: userData.feelTemp
})
})
// Don't forget the command to nodemon to see changes on hbs files
// nodemon server.js -e js,hbs,html,css
app.listen(port, () => {
console.log(`Server is up on ${port}`)
})
Here is my fetch.js file
// 3rd part library
const axios = require('axios')
// Input selection
const locationInput = document.querySelector('#locationInput').value()
// Encode user data & Use it to fetch his location
const encodedAddress = `greece${encodeURIComponent(locationInput)}`
const geocodeUrl = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodedAddress}&key=AIzaSyAnzbpJRrrx9xl2ZjRdwOx4APrn-zgVscM`
const getWeatherData = async (encodedAddress) => {
const location = await axios(geocodeUrl)
if (location.data.status === 'ZERO_RESULTS') {
throw new Error('Unable to find that address.')
}
const lat = location.data.results[0].geometry.location.lat
const long = location.data.results[0].geometry.location.lng
const weatherUrl = `https://api.darksky.net/forecast/95886b065ed14ca53b317610064fe04a/${lat},${long}?units=ca`
const weatherData = await axios.get(weatherUrl)
return {
location,
weatherData
}
}
getWeatherData(encodedAddress).then((info) => {
const location = info.location.data.results[0].formatted_address
const currentTemp = info.weatherData.data.currently.temperature
const feelTemp = info.weatherData.data.currently.apparentTemperature
return {
location,
currentTemp,
feelTemp
}
}).catch((e) => {
if (e.code === 'ENOTFOUND') {
console.log('Unable to connect to API servers')
} else {
console.log(e.message)
}
})
module.exports = {
location,
currentTemp,
feelTemp
}
And here is my html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Home</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
{{> header}}
<p>{{welcomeMessage}}</p>
<p>This is home page</p>
<input id="locationInput" type="text" placeholder="Location">
<p>{{location}}</p>
<p>{{currentTemp}}°C</p>
<p>Feels like {{feelTemp}}°C</p>
{{> footer}}
</body>
</html>
You can use event onchange of that input to send request like ajax or socket.io,etc.
onchange may be is different (onChange in reactjs, .change() method for jquery, ...)