How to send a SOAP request with Jest and Supertest? - soap

What I need is to send a SOAP request, which is a XML file.
How I can send the content which is a XML file as a post request?

Here is an example:
app.js:
const express = require('express');
const app = express();
const xmlparser = require('express-xml-bodyparser');
app.use(xmlparser());
app.post('/', (req, res) => {
res.json(req.body);
});
module.exports = app;
app.test.js:
const app = require('./app');
const request = require('supertest');
describe('57353993', () => {
// read from XML file
var itemsXML = '<list><item>item1</item><item>item2</item><item>item3</item></list>';
var itemList = {
list: {
item: ['item1', 'item2', 'item3'],
},
};
it('should pass', async () => {
const res = await request(app)
.post('/')
.set('Content-Type', 'application/xml')
.send(itemsXML);
expect(res.status).toBe(200);
expect(res.body).toEqual(itemList);
});
});
Test result:
PASS src/stackoverflow/57353993/app.test.js (9.465s)
57353993
✓ should pass (56ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.598s, estimated 11s

You should be able to do this:
const xml = "<note><to>Hello</to><from>World</from></note>"
const res = await request(app)
.post('/')
.set('Content-Type', 'application/xml')
.send(xml);

Related

phantomjs unable to open local file

I am able to get the content of http://example.com but not the index.html which is in my code with phantomjs. I see the filePath is correct.
'use strict';
const express = require('express');
const phantom = require('phantom');
const path = require('path');
// Constants
const PORT = 8888;
const HOST = '0.0.0.0';
// App
const app = express();
app.get('/', (req, res) => {
(async function() {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', function(requestData) {
console.info('Requesting', requestData.url);
});
const status = await page.open(getFileUrl('index.html'));
const content = await page.property('content');
console.log(content);
await instance.exit();
})();
});
function getFileUrl(str) {
var pathName = path.resolve( str );
if (pathName[0] !== "/") {
pathName = "/" + pathName;
}
return encodeURI("file://" + pathName);
};
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
Output
Running on http://0.0.0.0:8888
Requesting file:///home/codex/code/target-data-app/index.html
<html><head></head><body></body></html>

FetchError: invalid json response body at http://localhost:3000/api/products/6092ca3460fc67315178f2fa reason: Unexpected token < in JSON at position 0

I am trying to fetch data from MongoDB, but apparently, it gives an error
FetchError: invalid json response body at
http://localhost:3000/api/products/6092ca3460fc67315178f2fa reason: Unexpected token < in JSON at position 0
const defaultEndpoint = 'http://localhost:3000/api/products/';
export const getStaticPaths = async () => {
const res = await fetch(defaultEndpoint);
const data = await res.json();
const paths = data.map (product => {
return {
params: { id: product._id.toString() }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch ('http://localhost:3000/api/products/' + id);
const data = await res.json ();
return {
props: {product: data}
}
}
const Details = ({product}) => {
return (
<div>
<h1>{product.title}</h1>
</div>
)
}
export default Details
API Endpoint which is perfectly working on http://localhost:3000/api/products
import { connectToDatabase } from "../../util/mongodb";
export default async (req, res) => {
const { db } = await connectToDatabase();
const products = await db.collection("products").find({}).toArray();
res.json(products);
};

loging response from server does not work

I am following a tutorial from Coding Garden. There he writes to a database and sends it then back to the client.
When I try to do it, I do not get a respond from the server. I guess there has been a mix up in my code.
When I go to localhost/5000/posts there is no database. Why do I not get an errormessage, or a database?
Best regards
Expected Result:
https://youtu.be/JnEH9tYLxLk?t=3060
client code
const form = document.querySelector('form');
const loadingElement = document.querySelector(".loading");
const API_URL = "http://localhost:5000/posts";
loadingElement.style.display = "none";
form.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(form);
const name = formData.get('name');
const content = formData.get('content');
const post = {
name,
content
};
form.style.display = "none";
loadingElement.style.display= "";
fetch(API_URL, {
method: "POST",
body: JSON.stringify(post),
headers: {
"content-type": "application/json"
}
}).then(response => response.json())
.then(createdPost => {
console.log(createdPost);
});
});
server code
const express = require("express");
const cors = require('cors');
const monk = require("monk");
const app = express();
const db = monk("localhost/posts");
const posts = db.get("posts");
app.use(cors());
app.use(express.json());
app.get("/", (req, res) => {
res.json({
message: "Post"
});
});
function isValidPost(post){
return post.name && post.name.toString().trim() !== "" &&
post.content && post.content.toString().trim() !=="";
}
app.post("/posts", (req, res) => {
if (isValidPost(req.body)){
const post = {
name: req.body.name.toString(),
content: req.body.content.toString(),
created: new Date()
};
//console.log(post);
posts
.insert(post)
.then(createdPost => {
res.json(createdPost);
});
}else {
res.status(422);
res.json({
message: "Hey, Titel und Inhalt werden benötigt!"
});
}
});
app.listen(5000, () => {
console.log('Listening on http://localhost:5000');
});
You forgot to handle the case when post.insert(...) fails and rejects. In this case no response is sent from your server and the request will hang. Add the following:
posts
.insert(post)
.then(createdPost => {
res.json(createdPost);
})
.catch(err => {
console.log(err);
res.status(500).json({errorMessage: err.message});
});
handle the fetch method with catch. It probably goes to catch.
fetch().then().catch(err => ...)

Puppeteer Generate PDF from multiple HTML strings

I am using Puppeteer to generate PDF files from HTML strings.
Reading the documentation, I found two ways of generating the PDF files:
First, passing an url and call the goto method as follows:
page.goto('https://example.com');
page.pdf({format: 'A4'});
The second one, which is my case, calling the method setContent as follows:
page.setContent('<p>Hello, world!</p>');
page.pdf({format: 'A4'});
The thing is that I have 3 different HTML strings that are sent from the client and I want to generate a single PDF file with 3 pages (in case I have 3 HTML strings).
I wonder if there exists a way of doing this with Puppeteer? I accept other suggestions, but I need to use chrome-headless.
I was able to do this by doing the following:
Generate 3 different PDFs with puppeteer. You have the option of saving the file locally or to store it in a variable.
I saved the files locally, because all the PDF Merge plugins that I found only accept URLs and they don't accept buffers for instance. After generating synchronously the PDFs locally, I merged them using PDF Easy Merge.
The code is like this:
const page1 = '<h1>HTML from page1</h1>';
const page2 = '<h1>HTML from page2</h1>';
const page3 = '<h1>HTML from page3</h1>';
const browser = await puppeteer.launch();
const tab = await browser.newPage();
await tab.setContent(page1);
await tab.pdf({ path: './page1.pdf' });
await tab.setContent(page2);
await tab.pdf({ path: './page2.pdf' });
await tab.setContent(page3);
await tab.pdf({ path: './page3.pdf' });
await browser.close();
pdfMerge([
'./page1.pdf',
'./page2.pdf',
'./page3.pdf',
],
path.join(__dirname, `./mergedFile.pdf`), async (err) => {
if (err) return console.log(err);
console.log('Successfully merged!');
})
I was able to generate multiple PDF from multiple URLs from below code:
package.json
{
............
............
"dependencies": {
"puppeteer": "^1.1.1",
"easy-pdf-merge": "0.1.3"
}
..............
..............
}
index.js
const puppeteer = require('puppeteer');
const merge = require('easy-pdf-merge');
var pdfUrls = ["http://www.google.com","http://www.yahoo.com"];
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
var pdfFiles=[];
for(var i=0; i<pdfUrls.length; i++){
await page.goto(pdfUrls[i], {waitUntil: 'networkidle2'});
var pdfFileName = 'sample'+(i+1)+'.pdf';
pdfFiles.push(pdfFileName);
await page.pdf({path: pdfFileName, format: 'A4'});
}
await browser.close();
await mergeMultiplePDF(pdfFiles);
})();
const mergeMultiplePDF = (pdfFiles) => {
return new Promise((resolve, reject) => {
merge(pdfFiles,'samplefinal.pdf',function(err){
if(err){
console.log(err);
reject(err)
}
console.log('Success');
resolve()
});
});
};
RUN Command: node index.js
pdf-merger-js is another option. page.setContent should work just the same as a drop-in replacement for page.goto below:
const PDFMerger = require("pdf-merger-js"); // 3.4.0
const puppeteer = require("puppeteer"); // 14.1.1
const urls = [
"https://news.ycombinator.com",
"https://en.wikipedia.org",
"https://www.example.com",
// ...
];
const filename = "merged.pdf";
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
const merger = new PDFMerger();
for (const url of urls) {
await page.goto(url);
merger.add(await page.pdf());
}
await merger.save(filename);
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;

How to use mockgoose (or any other db mocking) in express app integration test

Using mockgoose in a simple unit test is quite straight-forward. However I'm a bit fuzzy as to how one would go about using mockgoose or other mocking solutions in an acceptance or integration test.
Given a simple express/MongoDB app like the following:
/*app.js*/
const express = require('express')
const app = express()
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var greetingSchema = mongoose.Schema({
greeting: String
});
var Greeting = mongoose.model('Greeting', greetingSchema);
app.get('/', function (req, res) {
Greeting.find({greeting: 'Hello World!'}, function (err, greeting){
res.send(greeting);
});
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
and a simple integration test like this:
/*test.js*/
const app = require('app.js');
const request = require('supertest');
it('sends "Hello World!" on the response body', (done) => {
request(app)
.get('/')
.expect(200, 'Hello World!', done);
});
});
By using the actual app in the request, we are connecting to the app's database ('mongodb://localhost/test'). How then can one use mockgoose, or any other solution, to mock the MongoDB database and still run an integration test like the one shown above?
I had the same problem as you. In my case, I solved using chai + chai-http and breaking the db connection and app in different files:
db.js:
const mongoose = require('mongoose');
const config = require('../../config');
mongoose.Promise = global.Promise;
mongoose.set('debug', process.env.DEBUG != undefined);
function open(){
return new Promise((resolve, reject) => {
if(process.env.DEBUG != undefined) {
let Mockgoose = require('mockgoose').Mockgoose;
let mockgoose = new Mockgoose(mongoose);
mockgoose.helper.setDbVersion("** your mongodb version **");
mockgoose.prepareStorage().then(function() {
mongoose.connect(config.db_test, (err, res) => {
if (err) return reject(err);
resolve();
});
}).catch(reject);
}else{
mongoose.connect(config.db, (err, res) => {
if (err) return reject(err);
resolve();
});
}
});
}
function close(){
return mongoose.disconnect();
}
module.exports = { close, open };
app.js:
const express = require('express');
const bodyParser = require('body-parser');
const api = require('./routes');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use('/api', api);
module.exports = app;
test.js (for test):
const chai = require('chai');
const chaiHttp = require('chai-http');
const expect = chai.expect;
const conn = require('./../utils/db'); // <-- db.js
const app = require('../../app'); // <-- app.js
chai.use(chaiHttp);
describe('# Test', function(){
before(function(done) {
conn.open().then(() => done()).catch(done);
});
after(function(done){
conn.close().then(() => done()).catch(done);
});
it(`test something`, function(done){
chai.request(app) // <-- pass the app here
.get('/path/to/test')
.then((res) => {
// expects
done();
})
.catch((err) => {
done(err);
});
});
});
index.js (for development or production):
const conn = require('./utils/db'); // <-- db.js
const app = require('./app'); // <-- app.js
const config = require('./config');
conn.open().then(() => {
app.listen(config.port, () => {
// OK!
});
});
I hope it works for you or anyone.