Unable to create a Pool instance with constructor in jest test - node.js

When I run a jest test, creating a Pool instance when I require the pool, it returns a _pg.Pool is not a constructor error.
I have tried looking at the StackOverflow: pg.Pool is not a constructor
And this still does not work.
However, I am able to create a pool instance when I run the code, the error only shows up in Jest.
Node code:
import { Pool } from 'pg'
const pool = new Pool({configs})
export default pool
Error log:
● Test suite failed to run
TypeError: _pg.Pool is not a constructor
> 6 | const pool = new Pool({
|
at Object.<anonymous> (src/resources/connection.js:6:14)
at Object.require (src/routes/api.js:2:20)
at Object.<anonymous> (src/__tests__/integration/user.test.js:8:1)
sidenote: the code is a copy of the documentation in https://node-postgres.com/api/pool
I don't expect an error to occur, since pg.Pool is a class with a constructor.

In case anyone comes across the same problem, I solved it by installing pg-pool, which has been merged into main pg package, and then importing pg-pool's Pool instead of pg's.
Reference: https://github.com/brianc/node-postgres/tree/master/packages/pg-pool

I wanted to add an alternate answer because for me the issue was very subtle and simple to fix.
I have a wrapper module that leverages pg and which historically has imported it via:
import * as postgresql from 'pg';
I've always used this.pool = new postgresql.Pool( { ...bits } );
This of course led to the following error today when updating my module to be pure ESM:
TypeError: postgresql.Pool is not a constructor
at new PostgreSQLDriver (file:///home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/dist/src/postgresql-database-driver.mjs:35:278)
at file:///home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/dist/test/postgresql-database-driver.mjs:23:559
at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:528:24)
at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15)
at async formattedImport (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/nodejs/esm-utils.js:7:14)
at async exports.loadFilesAsync (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/nodejs/esm-utils.js:91:20)
at async singleRun (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/cli/run-helpers.js:125:3)
at async exports.handler (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/cli/run.js:370:5)
I tried using named exports as the documentation seems to suggest in the Check, use, return section, but that got me:
file:///home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/dist/src/postgresql-database-driver.mjs:23
cov_1u3o9s5ali=function(){return actualCoverage;};}return actualCoverage;}cov_1u3o9s5ali();import{Pool}from'pg';import{DatabaseDriver}from'#kwaeri/database-driver';// You'll need this line and the method definitions below
^^^^
SyntaxError: Named export 'Pool' not found. The requested module 'pg' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from 'pg';
const {return actualCoverage;};}return actualCoverage;}cov_1u3o9s5ali();import{Pool}from'pg';import{DatabaseDriver} = pkg;
... As I had actually expected it would.
Anyways, the fix is hinted to by typescript in the syntax error above - doh:
import Postgres from `pg`;
// ...
this.pool = new Postgres.Pool( { ...bits } );
That resolves the issue.

Related

Why isn't my Node package being imported?

I'm learning Node.js and am using a Node-based Azure Function.
I'm trying to bring in Chalk, to log coloured messages to the console.
However, all of the below fail (in my main index.js file).
One
module.exports = async (ctx, req) => {
const chalk = require('chalk');
return console.log(chalk.blue('Hello world!'));
Despite being the approach recommended in this answer, this results in a console error that says:
Exception: require() of ES Module C:...\node_modules\chalk\source\index.js from C:...\index.js not supported.
Instead change the require of C:...\chalk\source\index.js in C:...\index.js to a dynamic import() which is available in all CommonJS modules.
Two
If I do as the error suggests, and use
const chalk = async import('chalk')
...I then get
Exception: chalk.blue is not a function
...even though console.log(chalk) does seem to show the Chalk API and its various properties.
Three
The Chalk docs themselves recommend this:
module.exports = async (ctx, req) => {
import chalk from 'chalk'
return console.log(chalk.blue('Hello world!'));
That yields an error saying I can't use import outside of a module (but surely I'm in one?)
Four
Same as three ^^ but moving the import outside module.exports:
import chalk from 'chalk'
module.exports = async (ctx, req) => {
return console.log(chalk.blue('Hello world!'));
...yields the same error.
I'm sure this is a basic error but I can't find what I'm doing wrong so I'd be so grateful if someone could help. Thank you!
When you import something using import as a function(lazy import), It'll return an object with a default property and all exported properties. That you should use to access the module.
const module = async import('chalk')
const chalk = module.default
console.log(chalk.red('Hello world!'))

Using serverless deployment to lambda with ES6 /Node.js v16

Newbie question....
I have a locally working node.js application which I am now trying to deploy express to AWS lambda. I have used this guide to deploy a test version (which worked).
I now am trying to implement my application which uses ES6 (and has type: module in package.json).
In my application I have added
import serverless from 'serverless-http'
but I cannot figure out the appropriate syntax for the export - the original was...
module.exports.handler = serverless(app);
I have tried:
const handler = async (app) =\> {
return serverless(app)
}
export default handler
Error message received:
2022-11-05T15:50:25.962Z undefined ERROR Uncaught Exception
"errorType": "Runtime.HandlerNotFound",
"errorMessage": "app.handler is undefined or not exported",
"stack": [
"Runtime.HandlerNotFound: app.handler is undefined or not exported",
" at Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:979:15)",
" at async start (file:///var/runtime/index.mjs:1137:23)",
" at async file:///var/runtime/index.mjs:1143:1"
]
I strongly suspect I am missing some fundamental understanding - truly appreciate some guidance.
The reason for the error is that you are sending a default export when AWS Lambda is expecting a named export.
The issue is the same as with all ES6 imports/exports:
// export.js
export default const defaultExport = "foo"
export const namedExport = "bar"
// import.js
import { defaultExport } from "./export.js" // error, cannot find defaultExport
import { namedExport } from "./export.js" // success, found namedExport
import defaultExport from "./export.js" // success, found defaultExport
So, it's like the case above where you're sending the defaultExport, but AWS Lambda wants the { namedExport }. You just need to remove default from your export, and make sure you're building the handler properly. Here is a suggestion to do that:
const lambda = serverless(app)
export async function handler(event, context) {
return lambda(event, context)
}
I've tested and it's working with serverless-offline using Node18.x. You can read more about exports on MDN.

uuid is not a function while using jest

I have the following setup:
// uuid-wrapper.ts
import { v4 as uuidV4 } from 'uuid';
const uuid: () => string = uuidV4;
export { uuid };
// uuid-wrapper.spec.ts
import { uuid } from './uuid-wrapper';
describe('uuid-wrapper', () => {
console.log(uuid());
});
This works fine runtime, but it breaks in test. I'm trying to migrate to Jest 29 and I'm getting the following error:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { default as v1 } from './v1.js';
^^^^^^
SyntaxError: Unexpected token 'export'
From uuid's repo I found a workaround which, after applied and my jest.config.js looks like this:
module.exports = {
moduleNameMapper: {
uuid: require.resolve("uuid"),
},
};
This gives me a different error but I still have no idea what it means:
> jest uuid-wrapper --no-coverage
FAIL src/uuid-wrapper/uuid-wrapper.spec.ts
● Test suite failed to run
TypeError: (0 , uuid_wrapper_1.uuid) is not a function
In fact, any function I export from this file (uuid-wrapper.ts) is not resolved. I have other tests that follow a similar pattern of reexporting packages but only this one breaks. I'm using uuid 9.0.0 and jest 29.1.2.
Edit: After a bit more testing, it turns out that anything I import into the test is "not a function".
uuid ships as an ESModule and Jest should not need to transform it. Add it to your transformIgnorePatterns in your Jest config:
module.exports = {
transformIgnorePatterns: ['node_modules/(?!(uuid))'],
}
Edit: After a bit more testing, it turns out that anything I import into the test is "not a function".
I had very similar symptoms once: builds and works as excepted, yet ...is not function in jest. The culprit was a circular dependency I accidentally introduced with my story. Maybe check for that.
As I suspected, the issue was in the naming. Renaming the files and directory to just wrapper solved the issue.

Cypress: Cannot use cy.task() to load dataset to Mongo before tests

I'm trying to use cy.taks() to load certain datasets to mongo before a test is run. But I'm getting errors. I've got a module where I export 2 functions, one from dropping a collection, and the other to load an object to a collection. Here is my cypress/plugins/index.js:
module.exports = (on, config) => {
on("task", {
"defaults:db": () => {
const {dropCollection, createUser } = require("../../lib/connectDB");
dropCollection("users");
createUser(userData)
},
});
};
Here is my /lib/connecDB.js:
export function dropCollection(collection) {
return mongoose.connection.dropCollection(collection);
}
export async function createUserInDB(userData) {
await User.create(userData);
}
So when I run the test, I'm getting:
cy.task('defaults:db') failed with the following error:
Unexpected token 'export'
Tried as well importing these function outside the index.js export, but getting same result.
I'd say it is something about export/import. The functions are exported as ES6, and imported as ES5.
I've tried to import the function the ES6 like:
import { dropCollection, createUser } from '../lib/connectDB'
And then export the plugin function also as ES6, but then I get:
Error: The plugins file is missing or invalid.
Your `pluginsFile` is set to `C:\Users\someRoute\cypress\plugins\index.js`, but either the file is missing, it contains a syntax error, or threw an error when required. The `pluginsFile` must be a `.js`, `.ts`, or `.coffee` file.
I've also tried to import required modules outside the function like:
const globalDbUtils = require('../lib/connectDB')
And then use the functions as
globalDbUtils.dropCollection("collectionName")
globalDbUtils.createUser(userData)
But I'm getting last error. I've tried pretty much everything, I tried to import Mongoose models straight, mongo client etc...Also I tried to import just one function and return it (just copy/pasting official doc...) but cannot make it work. I researched for a couple of days getting nothing, I found there is a npm package that helps u doing this, but since cypress allows you to do this by using no more plugins, I'd like to do it with no more tools than cypress itself.
Anyone knows what I am doing wrong?
Thanks in advance!
You need to use require instead of import at the top of your file and when exporting at the bottom use
module.exports = { createUserInDB }
Instead of exporting as you are currently doing.

Cannot use import statement outside a module in Lambda function

I have created a lambda function to get the list of items stored in dynamodb. Then i executed npm run build command after which i got .js files. I zipped the dist contents along with node modules, webpack.config.js and package.json and uploaded it. When i try to test it, am getting the following error. But there is no error in the code as far as i checked.
{
"errorType": "Runtime.UserCodeSyntaxError",
"errorMessage": "SyntaxError: Cannot use import statement outside a module",
"trace": [
"Runtime.UserCodeSyntaxError: SyntaxError: Cannot use import statement outside a module",
" at _loadUserApp (/var/runtime/UserFunction.js:98:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
" at Object.<anonymous> (/var/runtime/index.js:43:30)",
" at Module._compile (internal/modules/cjs/loader.js:956:30)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)",
" at Module.load (internal/modules/cjs/loader.js:812:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:724:14)",
" at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)",
" at internal/main/run_main_module.js:17:11"
]
}
I had the same error with node uuid module. Importing and using it as below fixed my issue:
'use strict';
const uuid = require('uuid'); // <-- how to import
exports.hello = async (event) => {
// ...
uniqueId = uuid.v4(); // <-- how to use it
// ...
};
I was ok with using require() for the longest time BUT certain packages like netlify cannot be loaded in lambda via require().
But AWS improved this ES vs commonJS import statement support early 2022... See here. Sadly not well described.
The following steps are maybe not perfect but worked for me:
Switch to NodeJs v14 on your AWS function if you didn't already
Pack the packages that you want to use once more and don't just have a nodejs folder but also a node14 folder. The node14 folder is mentioned here and I think essential. In case you forgot how to create lambda packages follow the docs here.
Create a lib.mjs file and load the package via import from /opt/nodejs/node14/node_modules/[my-package]/[maybe-some-subfolder]/index.js.
You can export what you need as object from lib.mjs and load it from index.js
lib.mjs:
// lib.mjs
import { NetlifyAPI } from "/opt/nodejs/node14/node_modules/netlify/src/index.js";
import { Route53Client } from "/opt/nodejs/node14/node_modules/#aws-sdk/client-route-53/dist-cjs/index.js";
export function loadPackages() {
return { NetlifyAPI, Route53Client };
}
Index.js:
//index.js:
import { loadPackages } from './lib.mjs';
export async function handler(event) {
const { NetlifyAPI, Route53Client } = loadPackages();
//TODO: business logic
}
This took me a long time to research and my approach is likely not perfect. I was forced to find a solution to load netflify and it only worked via import statement. I'm happy to get feedback in the comments and I am willing to adjust my tutorial accordingly.
Currently I'd generally still recommend to stick with require() if you can. If not I hope I could help.
PS: webpack is not needed in this approach.
This might be pretty late but i fixed mine by using require instead of import when importing modules
You have a problem with your import. Review your code (imports parts) and see if your IDE detects any errors. For my case, it was :
import Jimp from 'jimp/es'
I changed it to
import Jimp from 'jimp'
And now everything works.

Resources