I'm using PhantomJS as follows to retrieve and parse data from a website.
const phantom = require('phantom');
const url = 'https://stackoverflow.com/'
let _ph, _page, _outObj;
phantom.create()
.then( (ph) => {
_ph = ph;
return _ph.createPage();
}).then( (page) => {
_page = page;
return page.open(url);
}).then( (status) => {
console.log(`Status: ${status}`);
return _page.property('content');
}).then( (data) => {
console.log(data);
_page.close();
_ph.exit();
}).catch( (e) => console.log(e));
What I need to do also is to store the cookie send by the server and include them in subsequent requests to the server - how do I go about it ?
PhantomJS is capable of storing and loading cookies by itself, according to docs there is a cli option for that:
--cookies-file=/path/to/cookies.txt specifies the file name to store the persistent Cookies
So with phantom node module you pass this option upon browser creation:
phantom.create(['--cookies-file=/path/to/cookies.txt']).then(...)
Related
I'm new to cypress. My scenario is as follows:
1) Go to a test page.
2) Initiate an init script which interacts with the server and creates some session.
3) Go the backoffice
4) See that the new session appears in the table
The sessionId is received from the test page. When I initiate the session, I get the sessionId as a response (it is part of my test).
The problem is, that when I go to the backoffice (by using cy.visit) the whole cypress session resets, and I lose the sessionId.
I tried to use global variables and aliases, but to no avail.
Is there a way to pass the sessionId variable to the backoffice test?
Here's my code:
describe('Session init', () => {
let requestBody;
let responseBody;
let sessionId;
describe('Init the session in the client', () => {
before(() => {
cy.server();
cy.route({
method: 'POST',
url: initUrl,
onRequest: (xhr) => {
requestBody = xhr.request.body;
},
onResponse: (xhr) => {
responseBody = xhr.response.body;
}
}).as('init');
visitTestPage(); // uses cy.visit to go to the test page - also initiates a new session
});
it('should send POST init request', () => {
cy.wait('#init').then(() => {
expect(requestBody).to.contain.keys(
keysToExpectInRequest
);
});
});
it('should receive an init response', () => {
cy.wrap(responseBody.session).as('session');
sessionId = responseBody.session;
expect(responseBody).to.contain.keys(
keysToExpectInResponse
);
});
});
describe('Verify a session was created in backoffice', () => {
before(() => {
backofficeLogin(); // using cy.server and cy.visit, using premade jwt to avoid UI login
});
it('should see a live session with the id from the init', () => {
cy.get('.session-row').then((sessions) => {
expect(session[0].id).toEqual(sessionId); // expect the latest session created to be with the id of the session created in the test page
});
});
});
});
If you save the sessionId in the cookie you can use this:
cy.wrap(responseBody.session).as('session');
sessionId = responseBody.session;
cy.setCookie('sessionId', sessionId);
doc
But it is not recommended, because each test you perform must be independent of each other : doc
The Problem
I deployed a create-react-app webapp to aws ec2. It's used to display data from a database and send data to it. I use ExpressJS, CORS and MySQL.
With the following code i fetch the corresponding URL and the server.js sends back the database content. Until here, everything works fine.
getBets = _ => {
fetch("http://ec2***.amazonaws.com
.then(response => response.json())
.then(response => this.setState({bets: response.data}))
.catch(err => console.error(err))
};
The problem begins when sending data to the database with the following code:
addBet = _ => {
const { bet } = this.state;
fetch(`http://ec2***.amazonaws.com/bets/add?name=${bet.person_name}&bet=${bet.time_bet}`)
.then(response => response.json())
.then(this.getBets)
.catch(err => console.error(err))
};
On click the addBet-function populates the db, but in chrome I following error:
GET http://ec2***.amazonaws.com/bets/add?name=Peter%20Pan5&bet=10:17%205 net::ERR_EMPTY_RESPONSE
and
TypeError: Failed to fetch
Regarding chrome dev-tools, the first error corresponds to the fetch in the addBet function and the second error to the catch part.
On the server side I've the following code for processing the fetch:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES("${name}", "${bet}", CURTIME())`;
connection.query(INSERT_BET, (err, res) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I want to mention, that the res paramter in the app.get part is unused. That tells me my IDE.
After a lot of hours digging deeper in the topics of expressJS and the fetch api, I guess, that the app.get part doesn't send a response to the server. But the fetch need some response.
My Question
How do I have to change the code in the app.get part to send a proper response back to the server?
AND
Am I right with my guess?
In MYSQL when you do an insert query you get back err,results and fields in the callback function like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error,
results, fields) {
if (error) throw error;
console.log(results.insertId);
});
You have used the parameter res for result and then you have used res.send() which now corresponds to that res parameter in the callback function and not the res object.Rewrite it like this:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES(?,?,?)`;
connection.query(INSERT_BET,[name,bet,CURTIME()] ,(err, result) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I have also used prepared statement in place of normal sql queries. These are used to prevent sql injections. I hope it will work now.
I have an img tag in my html that requests the image from nodejs server. In my server js file I have below code to send image response but I observed data is not rendered on client side. Any suggestions?
const getFile = (filePath) => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, (error, data) => {
if (!error) {
resolve(data);
} // enter code here
else reject(error);
});
});
};
getFile(test.jpg).then((data) => {
response.statusCode = "200";
response.setHeader("Content-Type", "image/jpg");
response.end(data, "base64"); // Also tried response.end(data, "binary")
})
.catch(error => console.log(error));
Is this an Express application? If so, your best bet is to use the static middleware. Put all your static (binary) files in one folder, expose it with the static middleware, and load it that way.
Instead of fs.readFile, using fs.createReadStream and piping the chunks worked for images.
let frstream = fs.createReadStream(url);
response.statusCode = "200";
response.setHeader("Content-Type", "image/jpeg");
frstream.pipe(response);
We are using navigator.sendBeacon function to send data to Koa server, in which we are using bodyparser.
If we not wrapped data into form then by default this function send data as request payload. How I can able to access this data on Koa server?
Example -
navigator.sendBeacon('http://localhost:3000/cookies/', 'test=payload')
At server, request body is blank.
Considering that
Koa does not parse request body, so you need to use either koa-bodyparser or koa-body,
koa-bodyparser by default has only json and form parsing enabled,
From your screenshot, it is clear that navigator.sendBeacon set the Content-Type to text,
You need to change the Koa server code, so that it parses text data.
Example:
const Koa = require('koa'),
bodyParser = require('koa-bodyparser'),
app = (module.exports = new Koa());
app.use(bodyParser({ enableTypes: ['json', 'text'] }));
app.use(async (ctx) => {
// ctx.request.body should contain the parsed data.
console.log('Received data:', ctx.request.body);
ctx.body = ctx.request.body;
});
if (!module.parent) app.listen(3000);
Tested with
koa 2.7.0,
koa-bodyparser 4.2.1.
Although koa doesn't parse request body and for some reason you don't want to use koa-bodyparser you can still use the raw http to collect the body from request object.
app.use(async (ctx) => {
try {
// notice that I'm wrapping event emitter in a `promise`
ctx.body = await new Promise((resolve, reject) => {
let data = '';
// this is same as your raw `http.request.on('data', () => ()`
ctx.req.on('data', chunk => {
data += chunk;
};
ctx.req.on('error', err => {
reject(err);
};
ctx.req.on('end', () => {
resolve(data);
};
});
} catch (e) {
console.error(e);
}
});
I am trying to call a rest API from Firebase function which servers as a fulfillment for Actions on Google.
I tried the following approach:
const { dialogflow } = require('actions-on-google');
const functions = require('firebase-functions');
const http = require('https');
const host = 'wwws.example.com';
const app = dialogflow({debug: true});
app.intent('my_intent_1', (conv, {param1}) => {
// Call the rate API
callApi(param1).then((output) => {
console.log(output);
conv.close(`I found ${output.length} items!`);
}).catch(() => {
conv.close('Error occurred while trying to get vehicles. Please try again later.');
});
});
function callApi (param1) {
return new Promise((resolve, reject) => {
// Create the path for the HTTP request to get the vehicle
let path = '/api/' + encodeURIComponent(param1);
console.log('API Request: ' + host + path);
// Make the HTTP request to get the vehicle
http.get({host: host, path: path}, (res) => {
let body = ''; // var to store the response chunks
res.on('data', (d) => { body += d; }); // store each response chunk
res.on('end', () => {
// After all the data has been received parse the JSON for desired data
let response = JSON.parse(body);
let output = {};
//copy required response attributes to output here
console.log(response.length.toString());
resolve(output);
});
res.on('error', (error) => {
console.log(`Error calling the API: ${error}`)
reject();
});
}); //http.get
}); //promise
}
exports.myFunction = functions.https.onRequest(app);
This is almost working. API is called and I get the data back. The problem is that without async/await, the function does not wait for the "callApi" to complete, and I get an error from Actions on Google that there was no response. After the error, I can see the console.log outputs in the Firebase log, so everything is working, it is just out of sync.
I tried using async/await but got an error which I think is because Firebase uses old version of node.js which does not support async.
How can I get around this?
Your function callApi returns a promise, but you don't return a promise in your intent handler. You should make sure you add the return so that the handler knows to wait for the response.
app.intent('my_intent_1', (conv, {param1}) => {
// Call the rate API
return callApi(param1).then((output) => {
console.log(output);
conv.close(`I found ${output.length} items!`);
}).catch(() => {
conv.close('Error occurred while trying to get vehicles. Please try again later.');
});
});