I have defined a function service in one of the file
import Category from '../models/Category.js';
export const AllCategories = () => {
console.log('hit');
const cursor = Category.find({});
console.log(cursor);
return cursor
}
export default {AllCategories}
I am importing this in the controller file
import express from 'express';
import categoryService from '../services/categories.js'
const router = express.Router();
export const getCategories = async(req,res) => {
try {
const categoriesInfo = categoryService.AllCategories
res.status(200).json(categoriesInfo)
} catch (error) {
res.status(404).json({ message: error.message });
}
}
export default router;
But the issue is that AllCategories is not getting run, what is wrong here
I also tried adding async/await
import Category from '../models/Category.js';
export const AllCategories = async () => {
try {
console.log("hit");
const cursor = await Category.find({});
console.log(cursor);
return cursor
} catch (error) {
return error
}
}
export default {AllCategories}
But still no luck
You're not calling the function, this saves it in the variable categoriesInfo:
const categoriesInfo = categoryService.AllCategories
To get its return value:
const categoriesInfo = await categoryService.AllCategories();
Note: I think you need to make it async if you're doing a db transaction so keep the second version and test it.
You can't use the ES module or ESM syntax by default in node.js. You either have to use CommonJS syntax or you have to do 1 of the following.
Change the file extension from .js to .mjs
Add to the nearest package.json file a field called type with a value of module
Related
I am writing a test that looks like this:
import { getAllUsers } from "./users";
import { getMockReq, getMockRes } from "#jest-mock/express";
import User from "../../models/User";
jest.mock("../../models/User", () => ({
find: jest.fn(), // I want to change the return value of this mock in each test.
}));
describe("getAllUsers", () => {
test("makes request to database", async () => {
const req = getMockReq();
const { res, next, clearMockRes } = getMockRes();
await getAllUsers(req, res, next);
expect(User.find).toHaveBeenCalledTimes(1);
expect(User.find).toHaveBeenCalledWith();
});
});
Within the jest.mock statement, I am creating a mock of the imported 'User' dependency, specifically for the User.find() method. What I would like to do is set the return value of the User.find() method within each test that I write. Is this possible?
This SO question is similar, but my problem is that I can't import the 'find' method individually, it only comes packaged within the User dependency.
Well after much trial and error, here is a working solution:
import { getAllUsers } from "./users";
import { getMockReq, getMockRes } from "#jest-mock/express";
import User from "../../models/User";
const UserFindMock = jest.spyOn(User, "find");
const UserFind = jest.fn();
UserFindMock.mockImplementation(UserFind);
describe("getAllUsers", () => {
test("makes request to database", async () => {
UserFind.mockReturnValue(["buster"]);
const req = getMockReq();
const { res, next, clearMockRes } = getMockRes();
await getAllUsers(req, res, next);
expect(User.find).toHaveBeenCalledTimes(1);
expect(User.find).toHaveBeenCalledWith();
expect(res.send).toHaveBeenCalledWith(["buster"]);
});
});
Note how I've used jest.spyOn to set a jest.fn() on the specific User find method, and I can use the UserFind variable to set the return value of the mock implementation.
the problem
I created a Shopify node.js app using the Shopify CLI and I want to display a simple bar under the header using a script tag. I used the script tag API to add a script tag
"script_tags": [
{
"id": 174240039086,
"src": "https://xxxxx.ngrok.io/script_tag",
}
]
And I also added a <div id="script-app"></div> into the theme, under the header.
Here is my script_tag.js file, located in /pages/script_tag.js
import ReactDOM from 'react-dom';
class TestScriptTag extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
<p>this is a bar</p>
</div>
);
}
}
ReactDOM.render(<TestScriptTag />, document.getElementById('script-app'));
export default TestScriptTag;
Lastly, here is my server.js (most of it is what came with the CLI):
import "#babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "#shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "#shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";
import { flushSync } from "react-dom";
const fs = require('fs');
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8083;
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: false,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
console.log("here")
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
const host = ctx.query.host;
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (topic, shop, body) =>
delete ACTIVE_SHOPIFY_SHOPS[shop],
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
ctx.redirect(`/?shop=${shop}&host=${host}`);
},
})
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.get("/", async (ctx) => {
const shop = ctx.query.shop;
// This shop hasn't been seen yet, go through OAuth to create a session
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
});
router.get("/script_tag", (ctx) => {
handleRequest(ctx);
});
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", verifyRequest(), handleRequest); // Everything else must have sessions
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
I am getting the error: document not defined.
What I've tried
I thought this is due to server side rendering, so I thought I could get around it by doing this:
if (typeof window !== "undefined") {
ReactDOM.render(<TestScriptTag />, document.getElementById('script-app'));
}
But still nothing renders and I get this when I inspect the shop page.
I've also tried changing the routing to this:
router.get("/script_tag", (ctx) => {
ctx.type = "module";
ctx.body = fs.createReadStream('./pages/script_tag.js')
});
But then I get an error about the import statement in script_tag.js - SyntaxError: Unexpected identifier '{'. import call expects exactly one argument.
I'm not sure what the proper way is to serve the javascript file I want to inject into the header. I feel like I'm missing something stupid. Please help!!
I have this problem in Next.js. I call the API in getInitialProps and pass the params to my components then it works when I use it in mu project. But when I want to build it gives me error that the params are undefined.
This is how I call my API and pass it to component:
import BlogItem from './blogItem'
import axios from 'axios'
import { withRouter } from 'next/router'
import { APIURL, replaceAll } from '../../../components/config'
const Post = (props) => {
return (
<BlogItem
services ={props.services }
/>
)
}
Post.getInitialProps = async ({ query }) => {
const id = query.id
const urlTitle = encodeURI(query.title)
const services = null;
try {
const response = await axios.get(`${APIURL}getservice`);
services = response.data.response.posts;
} catch (err) {
console.error(err)
}
return {
services
}
}
export default withRouter(Post)
It seems that you defined services as a const that contain null! the whole code seems fine. Try changing const to let:
Post.getInitialProps = async ({ query }) => {
const id = query.id
const urlTitle = encodeURI(query.title)
let services = null; //this line
try {
const response = await axios.get(`${APIURL}getservice`);
services = response.data.response.posts;
} catch (err) {
console.error(err)
}
console.log(services) //you should have the data right here
return {services}
}
Example :
Look at this example. Run it and navigate to /about page :
You need to make sure that your url params are passed into the querystring on the server, In your case, something like this:
server.get('/page/:uid/:id', (req, res) => {
const mergedQuery = Object.assign({}, req.query, req.params)
return app.render(req, res, '/page', mergedQuery);
})
Then your getInitialProps can get them straight from the query, regardless of where it loads.
I have a lot of middleware. Here is one of them. How can I test my middleware with type compliance and with context.state validation on typescript ?
async function internationalizationPlugin(
context: ParameterizedContext<AppState, AppContext>,
next: Next
) {
context.state.i18n = await (i18next as any).createInstance({
lng: context.state.language,
fallbackLng: 'en',
})
await next()
}
a linter will check for type compliances and will be able to customize them more. However, you would just need to make sure that you export the function to your test file and then run a expect(typeof context).to.be(ParameterizedContext<AppState, AppContext>) that's not 100% copy/pasteable code, but, I think that it is on the right track. Also, for testability it could be easier if you created a class out of your middlewares that way importing and testing are done easier.
It's my simple type support solution. I'm not sure if it is suitable for everyone.
import * as httpMocks from 'node-mocks-http'
import * as Koa from 'koa'
export interface MockContext<RequestBody = undefined> extends Koa.Context {
request: Koa.Context['request'] & {
body?: RequestBody
}
}
export const koaMockContext = <
State = Koa.DefaultState,
Context = MockContext,
RequestBody = undefined
>(
requestBody?: RequestBody
) => {
const req = httpMocks.createRequest()
const res = httpMocks.createResponse()
const app = new Koa<State, Context>()
const context = app.createContext(req, res) as MockContext<RequestBody> & Koa.ParameterizedContext<State, Context>
res.statusCode = 404
context.request.body = requestBody
return context
}
And example
import { AppContext, AppState } from './types'
import { koaMockContext } from './utils'
import { internationalizationPlugin } from '../src/internationalizationPlugin'
describe('internationalizationPlugin', () => {
const ctx = koaMockContext<AppState, AppContext>()
it('should not be undefined', async () => {
await internationalizationPlugin(ctx, async () => {})
expect(ctx.state.i18n).not.toBe(undefined)
})
})
I was trying to import the module dynamically in ES6 on Meteor application. But getting an error cannot find module. The same import works when I'm using the static import statement.
Please have a look at the below code -
const JOBS = ['update-report-cron'];
const jobs = {
start() {
JOBS.forEach((job) => {
console.log(`job ${job} has been started`);
let fileName = './' + job + '.js';
console.log(require(fileName));
})
}
};
module.exports = {jobs};
ERROR - Cannot find module './update-report-cron.js'
Try
export default const jobs = {
// your code
}
When you import, use
import { jobs } from './update-report-cron.js'
Ru's answer is not correct, not sure how it's your answer.
Try
export default const jobs = {
// your code
}
When you import, use
import jobs from './update-report-cron.js'