Mock API to give response based on request URL's dynamic part - automated-tests

I would like to mock API calls so that
request to
http://localhost:8080/api/test/<yyyy-mm-dd>
gives a response:
{date: <yyyy-mm-dd>, data: 'my cool data'}
where <yyyy-mm-dd> is not fixed (This request is made 7 times for last 7 days)
How can I create a mock for this in TestCafé? Note that response data depends on the request URL.

Place index.html and index.js files in the same folder. Then run testcafe chrome test.js command in your terminal.
index.html
<html>
<body>
<h1>Page</h1>
<button id="sendRequestBtn">Send request</button>
<code id='response'></code>
<script>
var sendRequestBtn = document.getElementById('sendRequestBtn');
var responseData = document.getElementById('response');
sendRequestBtn.addEventListener('click', function (){
fetch('http://localhost:8080/api/test/2019-07-12')
.then(response => {
return response.json();
})
.then(json => {
responseData.textContent = JSON.stringify(json, null, 4);
})
.catch(e => console.error(e));
});
</script>
</body>
</html>
test.js
import { RequestMock } from 'testcafe';
const mock = RequestMock()
.onRequestTo(/http:\/\/localhost:8080\/api\/test\/.*/)
.respond((req, res) => {
res.headers['access-control-allow-origin'] = '*'; // It's necessary because TestCafe load the page via file protocol in this example.
const dateUrlPart = req.path.replace('/api/test/', '');
res.setBody({
date: dateUrlPart,
data: 'my cool data'
});
});
fixture `Fixture`
.page('./index.html')
.requestHooks(mock);
test('test', async t => {
await t.click('#sendRequestBtn').wait(1000);
});

Related

Cypress API testing. Can not find property

I am developing Cypress tests for my API.
The response from my API in Postman is below:
{"infected" : false}
And my Cypress test is below:
describe("Testing the result after scanning file", () => {
it("Scan file", function () {
//Declarations
const fileName = 'example.json';
cy.fixture(fileName, 'binary')
.then((file) => Cypress.Blob.binaryStringToBlob(file))
.then((blob) => {
const formData = new FormData();
formData.append("file", blob, fileName);
cy.request({
method: 'POST',
headers: {
'content-type': 'multipart/form-data'
},
body: formData,
url: '/scan'
}).then(response => {
console.log('the response is: ', response.body)
expect(response.body).to.have.property('infected').and.eq(false);
});
})
});
});
In my browser, the Cypress test fails with the message:
assert expected {} to have property infected
I really have already broken my brain with this issue and still have no clue how to tackle it. Can anybody give me an idea what is going wrong?
Try converting the response to json, you may be seeing a string version of the data.
Postman output will not be helpful, it could be converting automatically in the background.
cy.request({
...
})
.then(response => response.json())
// OR
// .then(response => response.body.json())
.then(data => {
console.log('the data is: ', data) // better debug tool than Postman
expect(data).to.have.property('infected').and.eq(false);
});

Re-wrtie async function with async/await and store data in Firestore on CKEditor 5

I am using CK-editor 5 and trying to add "upload image" function. I created an adapter with the following example provided by Piyush (Source: https://noteyard.piyushdev.xyz/blogpost/62596290751435313d7f85b5). However, since I use firestore as backend storage and write all async functions with async/await. Is there any way I can re-write all these codes with async/await and store it in a firestore collection called "Images"? Document name can be random ID, and data key value can be "image". I tried to write by myself but failed. Besides, I only get an empty HTML page saying "Cannot GET /api/blogs/uploadImg" while checking out the API URL example provided, and I can't check how the API structure looks like".
full code:
function uploadAdapter(loader) {
return {
upload: () => {
return new Promise((resolve, reject) => {
const body = new FormData();
loader.file.then((file) => {
body.append("uploadImg", file);
fetch(`${API_URl}/${UPLOAD_ENDPOINT}`, {
method: "post",
body: body
})
.then((res => res.json()))
.then((res) => {
resolve({ default: `${API_URl}/${res.url}` })
})
.catch((err) => {
reject(err);
})
})
})
}
}
}
function uploadPlugin(editor) {
editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
return uploadAdapter(loader);
}
}
API URL with "Cannot GET /api/blogs/uploadImg":
const API_URl = "https://noteyard-backend.herokuapp.com"
const UPLOAD_ENDPOINT = "api/blogs/uploadImg";

excel4node fetch request with next.js api routes not triggering download

I am generating an excel file and want it to be downloaded for the client by triggering an API route using the Next.js framework. I am having trouble triggering the download by using fetch. The download can be triggered by window.open(//urlhere, '_self') but the API call using fetch gives this response on request:
API resolved without sending a response for /api/download?Students= this may result in stalled requests.
The excel4node documentation says we can send an excel document through an API like this:
// sends Excel file to web client requesting the / route
// server will respond with 500 error if excel workbook cannot be generated
var express = require('express');
var app = express();
app.get('/', function(req, res) {
wb.write('ExcelFile.xlsx', res);
});
app.listen(3000, function() {
console.log('Example app listening on port 3000!');
});
Here is my backend download.js which lives in pages/api/:
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import Link from "next/link";
import getPartners from "../../components/main";
import excel from "excel4node";
export default function handler(req, res) {
const students = req.query.Students.split(",");
const partners = JSON.stringify(getPartners(students));
let workbook = createExcelList(partners);
workbook.write("PartnerList.xlsx", res);
}
const createExcelList = (partnersJSON) => {
const workbook = new excel.Workbook();
const partnersObject = JSON.parse(partnersJSON);
/* Using excel4node a workbook is generated formatted the way I want */
return workbook;
};
export const config = {
api: {
bodyParser: true,
},
};
And here is the function that is triggered on a button press in the front end.
const makePartners = async () => {
let queryStudents = studentList.join(",");
const url = "http://localhost:3000/api/download?Students=" + queryStudents;
if (studentList.length !== 0) {
try {
const res = await fetch(url, {
headers: {
"Content-Type":
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
},
});
console.log(res);
} catch (e) {
console.log(e);
}
}
};
Which does not trigger the download. But using window.open(url, '_self) does. So, I can trigger the download by changing the function to the following. However I don't think this is the correct way of doing things and would like to be able to understand how to use fetch correctly.
const makePartners = () => {
let queryStudents = studentList.join(",");
const url = "http://localhost:3000/api/download?Students=" + queryStudents;
if (studentList.length !== 0) {
window.open(url, "_Self");
}
};
I am not sure if this is a Next.js issue or not. Does anyone have any insight? Any help would be appreciated.

Properly fetching cached responses from workbox service worker

I was experimenting with workbox and service workers in general. I tried using NetworkFirst Strategy for my api calls. Console seems its working as expected but I could not display the cached response from service worker. Same is happening when using CacheFirst, response is not recieved by my dom render scripts. Am I missing something?
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js');`
if (workbox) {
console.log(`Yay! Workbox is loaded 🎉`);
workbox.precaching.precacheAndRoute([]);
const cacheName = 'collection';
workbox.routing.registerRoute(
new RegExp('http://13.232.112.165/api/'),
workbox.strategies.networkFirst()
);
/*
const bgSyncPlugin = new workbox.backgroundSync.Plugin('post-req-queue', {
maxRetentionTime: 24 * 60 // Retry for max of 24 Hours
});
workbox.routing.registerRoute(
new RegExp("http://13.232.112.165/api/"),
workbox.strategies.networkOnly({
plugins: [bgSyncPlugin]
}),
'POST'
);
workbox.routing.registerRoute(
new RegExp("http://13.232.112.165/api/"),
workbox.strategies.networkOnly({
plugins: [bgSyncPlugin]
}),
'PUT'
);
workbox.routing.registerRoute(
new RegExp("http://13.232.112.165/api/"),
workbox.strategies.networkOnly({
plugins: [bgSyncPlugin]
}),
'DELETE'
);
*/
} else {
console.log(`Boo! Workbox didn't load 😬`);
}`
My Api call is as follows :
async function getAccounts() {
url = backend_uri+"accounts";
try{
var jsonResponse = await fetch(url, {headers: {
'Authorization' : "Token "+localStorage.getItem('user-token')
}});
const json = await jsonResponse.json();
const accounts = await json;
let renderString = "";
await accounts.forEach(element => {
renderString = renderString + `<div class='card'><div class='card-body'><strong>${element.name}</strong></div></div>`
});
containerElement.innerHTML += renderString;
}catch(e) {
console.log(e);
}
}
Should api calls in PWA made differently?
(I don't think your question is related to Workbox or PWAs; it appears to be more about using the Fetch API.)
There are some extra awaits and a few other issues that I see with your code; can you try the following?
async function getAccounts() {
const url = `${backend_uri}accounts`;
const response = await fetch(url, {
headers: {
'Authorization' : "Token "+localStorage.getItem('user-token')
},
});
const accounts = await response.json();
const divs = accounts.map(account => `<div class='card'>
<div class='card-body'>
<strong>${account.name}</strong>
</div>
</div>`);
containerElement.innerHTML += divs.join('');
}

why is http response.body empty

Whilst write tests for my express API I wanted to check that response.body had the html I expected in it.
I found that the response object has a body property but that it is empty. I found the html in the response.text property.
When I used Postman to examine the response, it uses the words header for the header details and body for the html data. This is what I expected. This difference is confusing me as I am just learning http.
I am not asking about my own code as I tried it with a different site (www.bbc.co.uk) and got the same thing.
Why is there a difference in the wording? What is response.body for if not the data being returned?
Here is the code used in my test. This is the ejs template;
<html>
<head></head>
<body>Hello again world!</body>
</html>
Here is the express app;
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.set('view engine', 'ejs');
app.get('/', function(req, res) {
res.status(200).render('index');
});
app.get('*', function(req, res){
res.status(404).send('what???');
});
app.listen(3000, function() {
console.log('Example app listening on port ' + port);
});
Here are the tests;
const chai = require('chai');
const chaiHttp = require('chai-http');
const expect = require('chai').expect;
chai.use(chaiHttp);
const api = 'www.bbc.co.uk';
describe('The phonics API', () => {
it('should return status', (done) => {
chai.request('http://localhost:3000')
.get('/')
.end((err, res) => {
expect(res).to.have.status(200);
expect(res.body).to.exist;
done();
});
});
it('should return an HTML file in the body', (done) => {
chai.request('http://localhost:3000')
.get('/')
.end((err, res) => {
expect(res).to.be.html;
done();
});
});
it('should return status 404 for wrong url', (done) => {
chai.request('http://localhost:3000')
.get('/resersa')
.end((err, res) => {
expect(res).to.have.status(404);
done();
});
});
it('should respond with a body', (done) => {
chai.request(api)
.get('/')
.end((err, res) => {
expect(res.body).to.exist;
console.log(res.body);
done()
});
});
});
In the last test I added console.log(res.body) to see what was there. It prints {}. When I change it to console.log(res.test) I get the html above.
When I use postman to GET http://localhost:3000 It has the html under a tab called body.

Resources