I trying to serve dynamic file using Hapi framework, but I got error like this => Error: Missing helper: "handlebars": Missing helper: "handlebars"
Tutorial that I watched : https://www.youtube.com/watch?v=NTrro_tLzu4&list=PLkqiWyX-_LotaQ9AuppIAXl0xyV-P5Ms-&index=6
Here's my code:
📁server.js
/* eslint-disable linebreak-style */
/* eslint-disable max-len */
'use strict';
const Hapi = require('#hapi/hapi');
const Inert = require('#hapi/inert');
const Vision = require('#hapi/vision');
const Handlebars = require('handlebars');
const path = require('path');
const routes = require('./routes');
const init = async () => {
// BUILD SERVER
// eslint-disable-next-line new-cap
const server = Hapi.Server({
host: 'localhost',
port: 1234,
routes: {
files: {
relativeTo: path.join(__dirname, 'static'),
},
},
});
// PLUGIN CONFIGURATION
// Add Hapi Plugin - Only Hapi Plugin Can Be Registered and Don't Forget
// To Install The Plugin First
// 'plugin' key is must
await server.register([
{
plugin: require('hapi-geo-locate'),
options: {
// to able track the user ip
enabledByDefault: true,
},
},
{
plugin: Inert,
},
{
plugin: Vision,
},
]);
// MAKE HANDLEBARS AVAILABLE
server.views({
engines: {
html: Handlebars,
},
path: path.join(__dirname, 'views'),
});
// ROUTE
server.route(routes);
// SERVER CONFIGURATION
await server.start();
console.log(`Server started on: ${server.info.uri}`);
};
process.on('unhandleRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
📁routes.js
/* eslint-disable linebreak-style */
/* eslint-disable max-len */
const {welcomePage,
servingDynmaicPage,
loginPage,
downloadPage,
locationPage,
usersPage,
gradePage,
unavailablePage} = require('./handler');
const routes = [
{
method: 'GET',
path: '/',
handler: welcomePage,
// options: {
// files: {
// relativeTo: path.join(__dirname, 'static'),
// },
// },
},
{
method: 'GET',
path: '/dynamicPage',
handler: servingDynmaicPage,
},
{
method: 'POST',
path: '/loginPage',
handler: loginPage,
},
{
method: 'GET',
path: '/downloads',
handler: downloadPage,
},
{
method: 'GET',
path: '/locationPage',
handler: locationPage,
},
{
method: 'GET',
path: '/users/{name?}',
handler: usersPage,
},
{
method: 'GET',
path: '/School',
handler: gradePage,
},
{
method: 'GET',
path: '/{any*}',
handler: unavailablePage,
},
];
module.exports = routes;
📁handler.js
/* eslint-disable linebreak-style */
/* eslint-disable max-len */
const welcomePage = (request, h) => {
return h.file('welcome.html');
};
const servingDynmaicPage = (request, h) => {
const data = {
name: 'Adit',
};
return h.view('index', data);
};
const loginPage = (request, h) => {
if (request.payload.username === 'Adit' && request.payload.password === '123') {
return h.file('login.html');
} else {
return h.redirect('/');
}
};
const downloadPage = (request, h) => {
return h.file('welcome.html', {
mode: 'attachment',
filename: 'welcome-download.html',
});
};
const locationPage = (request, h) => {
if (request.location) {
return request.location.ip;
} else {
return '<h1>Your Location is not enabled by default!</h1>';
}
};
const usersPage = (request, h) => {
if (request.params.name) {
return `<h1>Hello! ${request.params.name}</h1>`;
} else {
return `<h1>Hello! Stranger</h1>`;
}
};
const gradePage = (request, h) => {
return `<h1>Welcome to grade ${request.query.grade}</h1>`;
};
const unavailablePage = (request, h) => {
return h.redirect('/');
};
module.exports = {welcomePage,
servingDynmaicPage,
loginPage,
downloadPage,
locationPage,
usersPage,
gradePage,
unavailablePage};
Related
I have a function that I am trying to test. I want to test that lambda.invoke is called with the correct arguments, however my test keeps saying that .invoke is never called. I think I am spying incorrectly. How can I spy on the .invoke and the .promise function?
Here is the function:
/* Amplify Params - DO NOT EDIT
ENV
FUNCTION_EMAIL_NAME
STRIPE_ENDPOINT_SECRET
REGION
Amplify Params - DO NOT EDIT */
const stripe = require('stripe');
const AWS = require('aws-sdk');
/**
* #type {import('#types/aws-lambda').APIGatewayProxyHandler}
*/
exports.handler = async (event) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
const lambda = new AWS.Lambda({ region: process.env.REGION });
const sig = event.headers['Stripe-Signature'];
let stripeEvent;
try {
stripeEvent = stripe.webhooks.constructEvent(
event.body,
sig,
process.env.STRIPE_ENDPOINT_SECRET
);
} catch (err) {
return {
statusCode: 400,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
},
body: JSON.stringify(`Webhook Error: ${err.message}`),
};
}
// Handle the event
switch (stripeEvent.type) {
case 'payment_intent.succeeded':
// eslint-disable-next-line no-case-declarations
const paymentIntent = stripeEvent.data.object;
// Then define and call a function to handle the stripeEvent payment_intent.succeeded
try {
const result = await lambda
.invoke({
FunctionName: process.env.FUNCTION_EMAIL_NAME,
Payload: JSON.stringify({
...event,
pathParameters: {
userID: paymentIntent.metadata.userID,
},
body: JSON.stringify({
user: {
emailAddress: paymentIntent.metadata.email,
},
}),
}),
})
.promise();
if (result.StatusCode === 200) {
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
},
body: JSON.stringify('Email successfully sent!'),
};
}
} catch (err) {
console.log('Email failed!', err);
}
break;
// ... handle other stripeEvent types
default:
console.log(`Unhandled stripeEvent type ${stripeEvent.type}`);
}
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
},
body: JSON.stringify('Hello from Lambda!'),
};
};
And here is the failing test:
const AWS = require('aws-sdk');
const stripe = require('stripe');
const { handler } = require('./index');
const event = require('./event.json');
jest.mock('stripe');
jest.mock('aws-sdk');
describe('handler', () => {
const { env } = process;
beforeEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
jest.clearAllMocks();
jest.resetModules();
process.env = {
...env,
REGION: 'us-east-1',
FUNCTION_EMAIL_NAME: 'example_function_name',
STRIPE_ENDPOINT_SECRET: 'stripe_test_key',
};
});
afterEach(() => {
process.env = env;
});
it('should call the email lambda if payment intent succeeded', async () => {
const lambdaSpy = jest.spyOn(AWS, 'Lambda');
const stripeSpy = jest.spyOn(stripe.webhooks, 'constructEvent');
const test = jest.fn();
stripeSpy.mockReturnValue({
type: 'succeeded',
});
lambdaSpy.mockReturnValue({ invoke: test, promise: jest.fn() });
await handler(event);
expect(test).toHaveBeenCalled();
});
});
I am getting this error
Cannot find module 'httpsGet' from 'functions/getSecureString.test.js'
httpsGet() is my own function, and is at the button of getSecureString.js, and called by getSecureString(). httpsGet() uses the https module to get content from a website that requires client side certificates.
Question
I am trying to mock httpsGet() and I am guessing the problem I have is because it isn't included with require() and hence jest.mock('httpsGet') fails.
Can anyone figure out if that is the case, and how I should fix it?
Live example at: https://repl.it/#SandraSchlichti/jest-playground-4
getSecureString.test.js
const getStatusCode = require('./getSectureString');
jest.mock('httpsGet');
describe("getSecureString ", () => {
describe('when httpsGet returns expected statusCode and body includes expected string', () => {
let result;
beforeAll(async () => {
httpsGet.mockResolvedValue({
statusCode: 200,
body: 'xyz secret_string xyz'
})
result = await getSecureString({
hostname: 'encrypted.google.com',
path: '/',
string: 'secret_string',
statusCode: 200,
aftaleId: 1234,
certFile: 1234,
keyFile: 1234,
timeout: 1000,
})
});
it('should return 1', () => {
expect(result).toEqual(1)
})
});
describe('when httpsGet returns expected statusCode and body includes expected string', () => {
let result;
beforeAll(async () => {
httpsGet.mockResolvedValue({
statusCode: 200,
body: 'xyz secret_string xyz'
})
result = await getSecureString({
hostname: 'encrypted.google.com',
path: '/',
string: 'not_secret_string',
statusCode: 201,
aftaleId: 1234,
certFile: 1234,
keyFile: 1234,
timeout: 1000,
})
});
it('should return 0', () => {
expect(result).toEqual(0)
})
});
describe("when an exception is thrown", () => {
let result;
beforeAll(async () => {
// mockRejected value returns rejected promise
// which will be handled by the try/catch
httpsGet.mockRejectedValue({
statusCode: 200,
body: 'xyz secret_string xyz'
})
result = await getSecureString();
})
it('should return -1', () => {
expect(result).toEqual(-1)
})
});
});
getSecureString.js
const fs = require('fs');
const https = require('https');
var uuid = require('uuid');
const {v4: uuidv4} = require('uuid');
module.exports = async function getSecureString(options) {
options = options || {};
options.hostname = options.hostname || {};
options.path = options.path || '/';
options.string = options.string || {};
options.statusCode = options.statusCode || {};
options.aftaleId = options.aftaleId || {};
options.certFile = options.certFile || {};
options.keyFile = options.keyFile || {};
options.timeout = options.timeout || 0;
const opt = {
hostname: options.hostname,
port: 443,
path: options.path,
method: 'GET',
cert: fs.readFileSync(options.certFile),
key: fs.readFileSync(options.keyFile),
headers: {'AID': options.aftaleId
},
};
opt.agent = new https.Agent(opt);
try {
const r = await httpsGet(opt, options.timeout);
return (r.statusCode === options.statusCode && r.body.includes(options.string)) ? 1 : 0;
} catch (error) {
console.error(error);
}
};
function httpsGet(opts, timeout) {
return new Promise((resolve, reject) => {
const req = https.get(opts, (res) => {
let body = '';
res.on('data', (data) => {
body += data.toString();
});
res.on('end', () => {
resolve({body, statusCode: res.statusCode});
});
});
req.setTimeout(timeout, function() {
req.destroy('error');
});
req.on('error', (e) => {
console.error(e);
reject(e);
});
});
};
A function that is used in the same module it was declared cannot be spied mocked, unless it's consistently as a method of some object, which is cumbersome and incompatible with ES modules:
module.exports.httpsGet = ...
...
module.exports.httpsGet(...);
Otherwise a function should be moved to another module that can mocked, or should be tested as is. In this case underlying API (https.get) can be mocked instead.
I'm having a problem wanting to get priceIndex information on binance. This is the error I got when accessing it.
{"code":-2014,"msg":"API-key format invalid."}
The URL I use is this:
https://api.binance.com/sapi/v1/margin/priceIndex?symbol=BNBBTC&recvWindow=5000×tamp=1592407054950&signature=xxxxxxxx
<script>
export default {
data() {
return {
binance: {
restapi: {
apiUrl: 'https://api.binance.com',
endPoint: '/sapi/v1/margin/priceIndex',
method: 'GET',
},
config: {
apiKey: 'xxxxxxxxx',
secretKey: 'xxxxxxxxx',
},
},
formData: {
symbol: 'BNBBTC',
recvWindow: '5000',
timestamp: '',
}
}
},
methods: {
getTime(){
var vm = this;
vm.$http({
url: 'https://api.binance.com/api/v1/time',
method: 'GET',
}).then((res) => {
vm.formData.timestamp = res.body.serverTime;
}).catch((err) => {
//error
});
},
mainProcces(){
var vm = this;
const CryptoJS = require('crypto-js');
const qs = require('qs');
const dataQueryString = qs.stringify(vm.formData);
const dataSignature = CryptoJS.HmacSHA256(dataQueryString, vm.binance.config.secretKey).toString(CryptoJS.enc.Hex);
vm.requestData(vm.binance.restapi, vm.binance.config, dataQueryString, dataSignature);
},
requestData(restApi, config, dataStr, signature){
var vm = this;
vm.$http({
url: restApi.apiUrl+restApi.endPoint+'?'+dataStr+'&signature='+signature,
headers: {
'X-MBX-APIKEY': config.apiKey,
},
method: restApi.method,
}).then((res) => {
// success
}).catch((error) => {
// error
});
},
},
mounted() {
var vm = this;
vm.getTime();
setTimeout(function(){
vm.mainProcces();
}, 1000);
}
}
</script>
Trying to run apollo-server in hapi. I have working cookie authorization in hapi, but I can't control queries to graphql. validateFunc is not called on graphql queries.
validateFunc is called after login with http://localhost:8080/login
But queries to http://localhost:8080/graphql do not call validateFunc.
If i'll set auth mode of graphql to required, i'll receive not authorizaed error, but validateFunc still not called.
const Hapi = require("#hapi/hapi"); //v18.3.2
const { ApolloServer, gql } = require("apollo-server-hapi"); //v2.8.1
const typeDefs = gql`
type Query {
_: String
}
type Mutation {
_: String
}
`;
const resolvers = {
Query: {},
Mutation: {}
};
const runServer = async () => {
const server = new Hapi.server({ port: 8080 });
await server.register(require("#hapi/cookie"));
server.auth.strategy("session", "cookie", {
cookie: {
name: "test-project",
password:
"long-long-password-long-long-password-long-long-password-long-long-password",
isSecure: false
},
validateFunc: async (request, session) => {
console.log("Why it is not called on graphql queries???");
return { valid: true, credentials: "account" };
}
});
server.auth.default("session");
//GRAPH QL!
const graphqlServer = new ApolloServer({
typeDefs,
resolvers,
context: async function(q) {
console.log("Graphql context was called!");
return q;
},
introspection: false,
playground: true,
route: {
options: {
auth: {
mode: "try"
}
}
}
});
server.route([
{
method: "GET",
path: "/login",
handler: function(request, h) {
request.cookieAuth.set({ id: "key" });
return "LOGIN!";
},
options: {
auth: {
mode: "try"
}
}
},
{
method: "GET",
path: "/test",
handler: function(request, h) {
console.log("TEST");
return "OK";
},
options: {
auth: {
mode: "try"
}
}
}
]);
await graphqlServer.applyMiddleware({
app: server,
route: {
auth: { mode: "try" }
}
});
await graphqlServer.installSubscriptionHandlers(server.listener);
await server.start().then(() => {
console.log(`🚀 Server ready at ${server.info.uri}/graphql `);
});
};
runServer();
Expecting graphql queries execute hapi's validateFunc()
Hi I am migrating to Hapi 17 from 16. I have my routes defined in a different file which I am trying to register as a plugin. But I get a 404 when I call the API. The routes are not registered with the server.
This is my Server code.
'use strict'
const Hapi = require('hapi')
const server = new Hapi.Server({ port: 1234, host: 'localhost' });
const plugins = [{
plugin: require('vision'),
plugin: require('./methods/exampleMethod'),
plugin: require('./routes/devices')
}]
async function registerPlugin(){
await server.register(plugins)
}
registerPlugin().then( () => {server.start()})
This is my routes file devices.js:
exports.plugin = {
register: (server, options) =>
{
server.routes = [{
method: 'GET',
path: '/v1/devices',
handler: async function (request, h) {
const val = server.methods.testMethod("ankur")
const response = h.response('hello world ankur')
response.type('text/plain')
return response
}
}]
},
name: 'devices'
}
Methods file
exports.plugin = {
register: (server, options) => {
server.method(
{
name: 'testMethod',
method: function (id) {
return new Promise(function (resolve, reject) {
return resolve("Test method called")
})
}
})
},
name: "exampleMethod"
I am following the release notes for Hapi 17 and trying to register the routes as a custom plugin. However, when I hit the Get v1/devices I get a 404.
Following code for your routes file will work:
exports.plugin = {
register: (server, options) => {
server.route(
{
method: "GET",
path: "/v1/devices",
handler: async function(request, h) {
//const val = server.methods.testMethod("ankur")
const response = h.response("hello world ankur");
response.type("text/plain");
return response;
}
}
);
},
name: "devices"
};
You should call server.route() function with your route object.
If you like to register more than one function through your routes plugin use something like this:
exports.plugin = {
register: (server, options) => {
const routes = [
{
method: "GET",
path: "/v1/devices",
handler: async function(request, h) {
const response = h.response("hello world");
response.type("text/plain");
return response;
}
},
{
method: "GET",
path: "/v1/another",
handler: async function(request, h) {
const response = h.response("hello another world");
response.type("text/plain");
return response;
}
}
];
server.route(routes);
},
name: "devices"
};
Edit:
Methods plugin
exports.plugin = {
register: (server, options) => {
server.method("testMethod", async function(id) {
return "Test method called";
});
},
name: "exampleMethod"
};
Call the method:
{
method: "GET",
path: "/v1/example",
handler: async function(request, h) {
const response = await request.server.methods.testMethod();
return response;
}
}