TestCafe Triggering Test By POST Request In Express - node.js

I had a question that doesn't seem to be answered anywhere.
I am running tests from within my Express.js api. I set up a page that has a button and a field to enter a keyword intended to be used during a testcafe test. My endpoint I set up is /testcafe. But after sending a post request to /testcafe, there is a long delay while test runs and so my question is what is the best next step besides hanging?
Also, can my post request body, which contains the keyword, be directly used in a test like this? Keep in mind it's this pattern:
frontend -> POST request -> Express server -> /testcafe endpoint - test
My problem is after it reaches test, I currently have it attempting to call fetch from within the request logger. Is this right?
import { ClientFunction, Selector } from 'testcafe';
import { RequestLogger, RequestHook } from 'testcafe';
import zlib from 'zlib';
import fetch from 'isomorphic-unfetch';
const url = 'https://www.mysitetesturl.com/page';
class MyRequestHook extends RequestHook {
constructor (requestFilterRules, responseEventConfigureOpts) {
super(requestFilterRules, responseEventConfigureOpts);
}
onRequest (e) {
console.log('in onRequest!')
console.log('========================')
console.log('Request Body')
let buf = e._requestContext.reqBody
console.log(buf.toLocaleString())
}
onResponse (e) {
let buf = Buffer(e.body)
let unzippedBody = Buffer(zlib.gunzipSync(buf))
let payload = unzippedBody.toLocaleString()
fetch('http://myapiipaddress/api/testcafe',
method: 'PUT',
body: JSON.stringify(payload)
)
.then((err, doc) => {
if(err) {
console.log(err)
} else {
console.log(doc)
}
})
}
}
const myRequestHook = new MyRequestHook({
url: url,
method:'get'},
{
includeHeaders: true,
includeBody: true
}
);
fetch('http://myapiipaddress/api/testcafe',
method: 'GET'
)
.then((err, doc) => {
if(err) {
console.log(err)
} else {
fixture`myfixture`
.page(doc.url)
.requestHooks(myRequestHook);
test(`mytest`, async t => {
const inputField = Selector('input');
await t
await t
.wait(5000)
.typeText(inputField, doc.text)
.wait(5000)
}
);
}
})

According to your scheme, you need to organize your code in a different way:
const createTestCafe = require('testcafe');
....
// Choose the necessary body parser for express application
// https://github.com/expressjs/body-parser
app.use(bodyParser.urlencoded({ extended: true }));
...
app.post('/', function (req, res) {
createTestCafe('localhost', 1337, 1338, void 0, true)
.then(testcafe => {
const runner = testcafe.createRunner();
return runner
.src('/tests')
.browsers('chrome')
.run();
})
.then(failedCount => {
testcafe.close();
res.end();
});
})

Related

how to set headers in axios patch request in react js

Can someone tell me what mistake I am making or tell me how to set the header in axios patch request. when I am running the API through postman, everything is working fine but when I connect it with the front end, an error comes up saying that the JWT is not provided on the backend
here is the frond end code :
import React, { useEffect } from 'react';
import { useParams } from 'react-router';
import axios from 'axios';
const Loader = () => {
const parmas = useParams();
const { id } = parmas;
console.log(id);
useEffect(() => {
const fetchBags = async () => {
try {
const res = await axios.patch('http://localhost:4001/public/verify', {
headers: {
'Content-Type': 'application/json',
Token: id,
},
});
console.log(res);
console.log('CBM', { res });
} catch (error) {
console.log(error);
}
};
fetchBags();
}, []);
return <div>this is loader</div>;
};
export default Loader;
below is my backend code:
export const verifyUser = async (data) => {
const token1 = data.header("Token");
try {
const verified = jwt.verify(token1, getTokenSecret());
console.log(verified)
await userModel.verifyUser(verified);
return {
message: "success",
};
} catch (error) {
console.log(`Auth Service > verifyUser > ${error.toString()}`);
throw error;
}
};
this error is comming:
Error
From docs
axios.patch(url[, data[, config]])
As you can see you pass config in 3rd argument not 2nd.
const res = await axios.patch(
'http://localhost:4001/public/verify',
{}, // data (2nd argument)
{
headers: {
'Content-Type': 'application/json',
Token: id,
},
} // config (3rd argument)
)

Error: React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render

import { setCookies, removeCookies } from "cookies-next";
import { useRouter } from "next/router";
import { useEffect } from "react";
const { URL } = process.env;
export const getServerSideProps = async (context) => {
const userAuthToken = context.req.cookies["authToken"];
const data = {
authToken: userAuthToken,
};
const requestJSON = JSON.stringify(data);
const response = await fetch(URL + "api/userFetch", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: requestJSON,
});
const responseData = await response.json();
return {
props: { datas: responseData },
};
};
const Home = ({ datas }) => {
const router = useRouter();
if (datas[0].error == true) {
useEffect(() => {
setTimeout(() => {
router.push("/");
}, 3000);
}, []);
removeCookies("authToken");
return <h1>Something Went Wrong</h1>;
} else {
return <h1>Welcome To Home{datas[0].error}</h1>;
}
};
export default Home;
This code is running fine on development server but when I try to build this code in production I get this error **
./pages/Home.js
28:5 Error: React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?**
I tried everything I could but can't fix the error
Just do exactly what the error is telling you. Move the useEffect call out of the conditional block. You can still conditionally perform the operation within the hook. For example:
const Home = ({ datas }) => {
const router = useRouter();
useEffect(() => {
if (datas[0].error == true) {
setTimeout(() => {
router.push("/");
}, 3000);
}
}, []);
if (datas[0].error == true) {
removeCookies("authToken");
return <h1>Something Went Wrong</h1>;
} else {
return <h1>Welcome To Home{datas[0].error}</h1>;
}
};
Specifically, as the error states, the same hooks must always be called on every render. (I don't know enough under the hood of React to describe why that's the case, it just seems necessary for stability/consistency/etc.) But the operation being performed by the hook in this case can still be effectively a no-op if the intended condition is not met.

How do I send a HEAD request for a static sendFile in fastify?

When I try to send a HEAD request for sendFile I get the following error:
app.head(filePath, { logLevel: LOG_LEVEL }, async (request, reply) => {
console.log('head');
try {
const { '*': uriPath } = request.params;
const isFile = !!uriPath.match(/\.[a-zA-Z0-9]{1,5}(\?.*)?/);
if (isFile) {
setCacheControl(reply, FILE_CACHE_CONTROL_MAX_AGE);
reply.sendFile(uriPath);
} else {
const indexPath = 'index.html';
const indexStr = await fs.readFile(path.join(serveRoot, indexPath), {
encoding: 'utf-8',
});
const indexPayload = await injectEnv(indexStr);
setCacheControl(reply, INDEX_CACHE_CONTROL_MAX_AGE);
reply.type('text/html');
reply.send(indexPayload);
}
} catch (e) {
console.error(e);
}
});
web_1 | {"level":50,"time":1580244056047,"pid":1,"hostname":"3ee631923a16","reqId":5,"err":{"type":"FastifyError","message":"FST_ERR_PROMISE_NOT_FULLFILLED: Promise may not be fulfilled with 'undefined' when statusCode is not 204","stack":"FastifyError [FST_ERR_PROMISE_NOT_FULLFILLED]: FST_ERR_PROMISE_NOT_FULLFILLED: Promise may not be fulfilled with 'undefined' when statusCode is not 204\n at /usr/src/server/node_modules/fastify/lib/wrapThenable.js:34:30\n at processTicksAndRejections (internal/process/task_queues.js:85:5)","name":"FastifyError [FST_ERR_PROMISE_NOT_FULLFILLED]","code":"FST_ERR_PROMISE_NOT_FULLFILLED","statusCode":500},"msg":"Promise may not be fulfilled with 'undefined' when statusCode is not 204","v":1}
The way that express handles this is by simply passing through HEAD requests to the GET method, and then letting send (the underlying package that sends responses for both fastify and express) handle it here by not sending the output but sending the headers.
But fastify seems to incorrectly mark this as an error here
Here a working example:
const fs = require('fs').promises
const path = require('path')
const app = require('fastify')({ logger: true })
app.head('/', async (request, reply) => {
request.log.debug('head')
try {
const indexStr = await fs.readFile(path.join(__dirname, 'index.html'), { encoding: 'utf-8' })
reply.type('text/html')
return indexStr
} catch (e) {
request.log.error(e)
return e
}
})
app.listen(3000)
// curl --location --head 'http://localhost:3000/'
When an error is thrown and caught the promise is fulfilled with undefined that is causing the error you linked in the source code.
Moreover, when you use async functions as handlers, you should return what you want to send in the body or use return reply.send(content)
Anyway, consider to don't use HEAD methot because the standard says:
A response to a HEAD method should not have a body. If so, it must be ignored. Even so, entity headers describing the content of the body, like Content-Length may be included in the response. They don't relate to the body of the HEAD response, which should be empty, but to the body which a similar request using the GET method would have returned as a response.
So your body will be empty:
HTTP/1.1 200 OK
content-type: text/html
content-length: 41
Date: Wed, ---
Connection: keep-alive
Solved it. The key is to return the binary stream for filesreturn fs.readFile(uriPath); and the string for string responses return indexPayload;
import path from 'path';
import fastify from 'fastify';
import staticServe from 'fastify-static';
import { promises as fs } from 'fs';
(async () => {
const app = fastify({
logger: !!LOG_LEVEL,
});
const filePath = `${ROOT_PATH}*`;
const serveRoot = path.resolve(SERVE_PATH);
app.register(staticServe, {
root: serveRoot,
serve: false,
});
// #ts-ignore
const getHandler = async (request, reply) => {
try {
const { '*': uriPath } = request.params;
const isFile = !!uriPath.match(/\.[a-zA-Z0-9]{1,5}(\?.*)?/);
if (isFile) {
setCacheControl(reply, FILE_CACHE_CONTROL_MAX_AGE);
reply.sendFile(uriPath);
return fs.readFile(uriPath);
} else {
const indexPath = 'index.html';
const indexStr = await fs.readFile(path.join(serveRoot, indexPath), {
encoding: 'utf-8',
});
const indexPayload = await injectEnv(indexStr);
setCacheControl(reply, INDEX_CACHE_CONTROL_MAX_AGE);
reply.type('text/html');
return indexPayload;
}
} catch (e) {
request.log.error(e);
return e;
}
};
app.get(filePath, { logLevel: LOG_LEVEL }, getHandler);
// More info here on how it works
// https://github.com/fastify/fastify/issues/2061
app.head(filePath, { logLevel: LOG_LEVEL }, getHandler);
app.listen(Number.parseInt(PORT, 10), '0.0.0.0', (err: Error) => {
if (err) {
throw err;
}
});
})();

Sending file using restify with multipart/form-data causes a timeout problem

I have a problem because I am trying to implement file upload using multipart / form-data on my NodeJS server. When I call upload, the file I upload appears in the temporary server folder, but my request does not continue and my client is waiting for a response (in this case the uploadFile method is never running).
upload.router.ts
import {Router} from '../common/router';
import * as restify from 'restify';
class UploadRouter extends Router {
uploadFile = (req, resp, next) => {
console.log(req);
resp.json('test');
};
applyRoutes(application: restify.Server) {
this.basePath = '/upload';
application.post(`${this.basePath}`, this.uploadFile);
}
}
export const uploadRouter = new UploadRouter();
server.ts
export class Server {
application: restify.Server;
initRoutes(routers: Router[]): Promise<any> {
return new Promise((resolve, reject) => {
try {
const options: restify.ServerOptions = {
name: environment.project.name,
version: environment.project.version
};
if (environment.security.enableHTTPS) {
options.certificate = fs.readFileSync(environment.security.certificate);
options.key = fs.readFileSync(environment.security.key);
}
this.application = restify.createServer(options);
this.connector = blockchainConnector(environment.blockchain.connector);
const corsOptions: corsMiddleware.Options = {
preflightMaxAge: 10,
origins: ['*'],
allowHeaders: ['*'],
exposeHeaders: []
};
const cors: corsMiddleware.CorsMiddleware = corsMiddleware(corsOptions);
this.application.pre(cors.preflight);
this.application.use(cors.actual);
this.application.use(restify.plugins.queryParser());
this.application.use(restify.plugins.bodyParser());
this.application.use(restify.plugins.acceptParser(this.application.acceptable));
this.application.use(restify.plugins.fullResponse());
this.application.use(restify.plugins.multipartBodyParser({
multiples: true,
mapParams: true,
mapFiles: true,
keepExtensions: true,
uploadDir: environment.directory.tempDir
}));
this.application.use(mergePatchBodyParser);
this.application.use(tokenParser);
// routes
for (let router of routers) {
router.applyRoutes(this.application, this.connector);
indexRouter.addRouter(router);
}
indexRouter.applyRoutes(this.application);
this.application.listen(environment.server.port, () => {
resolve(this.application);
});
this.application.on('restifyError', handleError);
} catch (error) {
reject(error);
}
})
}
bootstrap(routers: Router[] = []): Promise<Server> {
return this.initRoutes(routers).then(() => this);
}
shutdown() {
this.application.close();
}
}
I realize that this is 8 months later, but it looks like you forgot to call next() in uploadFile

Thunk + Redux (in React Native) : Can't get action to work

I'm brand new to this stack. I've seen quite a few other questions about this and have read the Thunk documentation but I can't stitch this together.
When I run the code below I get the error "Actions must be plain objects, use custom middleware for async actions" which is exactly the problem I'm trying to solve with Thunk.
My action looks like this:
src/actions/recipes.js
// this calls the API
function fetchApiGetRecipes() {
return fetch('https://mywebsite.com/endpoint/', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + idToken
}
}).then((json) => {
dispatch({
type: 'RECIPES_REPLACE',
data: json
})
});
}
// this is passed into my container to use to refresh the recipe list
export function getRecipes() {
if (Firebase === null) return () => new Promise(resolve => resolve());
if (Firebase.auth().currentUser !== null) {
Firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// console.log(idToken);
return dispatch => new Promise(resolve => fetchApiGetRecipes(idToken) )
}).catch(function(error) {
// Handle error
});
} else {
console.log("Null user");
}
}
What is the correct syntax to use Thunk here and fix the error I'm getting when the app starts up?
EDIT: I create the store like this:
import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, persistCombineReducers } from 'redux-persist';
import storage from 'redux-persist/es/storage'; // default: localStorage if web, AsyncStorage if react-native
import thunk from 'redux-thunk';
import reducers from '../reducers';
// Redux Persist config
const config = {
key: 'root',
storage,
blacklist: ['status'],
};
const reducer = persistCombineReducers(config, reducers);
const middleware = [thunk];
const configureStore = () => {
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
compose(applyMiddleware(...middleware)),
);
const persistor = persistStore(
store,
null,
() => { store.getState(); },
);
return { persistor, store };
};
export default configureStore;
Your getRecipes function doesn't return a function in the if (Firebase.auth().currentUser !== null) clause.
You need to return a function where you are just doing
Firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// console.log(idToken);
return dispatch => new Promise(resolve => fetchApiGetRecipes(idToken) )
}).catch(function(error) {
// Handle error
});
The dispatch function (I assume is the intended one to return) is being returned in the then clause of the promise. That doesn't return the dispatch function to the outer method getRecipies. Hence the error
probably you forgot pass dispatch to func args?
// you use dispatch in this func
function fetchApiGetRecipes() {...}
// you forget pass
return dispatch => new Promise(resolve => fetchApiGetRecipes(idToken) )

Resources