Mocha testing path argument in package.json - node.js

Note: I'm a complete noob to nodejs. Please explain your answer in such a way somebody who has experience in other programming languages, but creates his very first nodejs application can understand =).
I'm trying to write a simple test application which should automate testing an external service against an OpenApi 3.0 specification.
I've pulled together some example code in order to attempt to automate testing the OpenApi spec against an external service which implements the API using mocha and chai.
My problem seems now that my mocha test modules cannot be found.
I get the following error message:
> client_test#1.0.0 test /Users/user1/dev/app/app-rt/client_test
> mocha ./test/**/*.test.js
/Users/user1/dev/app/app-rt/client_test/node_modules/yargs/yargs.js:1163
else throw err
^
Error: The "path" argument must be an absolute filepath
My package.json:
{
"name": "client_test",
"version": "1.0.0",
"description": "Client Tester",
"main": "index.js",
"scripts": {
"test": "mocha ./test/**/*.test.js"
},
"license": "UNLICENSED",
"dependencies": {
"chai-http": "^4.3.0",
"chai-openapi-response-validator": "^0.2.4",
"mocha": "^6.2.0",
"nock": "^11.3.2"
}
}
The little test application in test/client_all.test.js:
// Set up Chai
const chai = require('chai');
const expect = chai.expect;
// Import this plugin
const chaiResponseValidator = require('chai-openapi-response-validator');
const baseUrl = 'http://localhost:8081';
// Load an OpenAPI file (YAML or JSON) into this plugin
chai.use(chaiResponseValidator('./spec/app.json'));
// Get an HTTP response using chai-http
chai.use(require('chai-http'));
// Write your test (e.g. using Mocha)
describe('GET /zones', function() {
it('should satisfy OpenAPI spec', async function() {
const res = chai.request(baseUrl).get('/zones');
expect(res.status).to.equal(200);
// Assert that the HTTP response satisfies the OpenAPI spec
expect(res).to.satisfyApiSpec;
});
});
Can you help me figure out why the paths cannot resolved, and how to fix it? Feel free to comment on the test code as well, if you think I'm doing it wrong.

The problem is with the package chai-openapi-response-validator. Try something like this:
// Import this plugin
const chaiResponseValidator = require('chai-openapi-response-validator');
const baseUrl = 'http://localhost:8081';
// New code
const path = require('path')
const specPath = path.resolve('./spec/app.json')
// Load an OpenAPI file (YAML or JSON) into this plugin
chai.use(chaiResponseValidator(specPath));
Make sure the path to the app.json file is relative to the package.json file, or use another method to convert it to an absolute path.

Related

AWS AmplifyAUTH: flutter: [ERROR]: CreateAuthChallenge failed with error SyntaxError: await is only valid in async function

Getting the captioned error message onTap signUpButton() within AuthenticatorForm(). Seems like a very idiomatic error message, but can't seem to find what's wrong.
Here is my createAuthChallenge.js
const AWS = require('aws-sdk');
const digitGenerator = require('crypto-secure-random-digit');
function sendSMS(phone, code) {
const params = {
Message: code,
PhoneNumber: phone,
};
return new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
}
async function createAuthChallenge(event) {
if (event.request.challengeName === 'CUSTOM_CHALLENGE') {
const randomDigits = digitGenerator.randomDigits(6).join('');
const challengeCode = String(randomDigits).join('');
await sendSMS(event.request.userAttributes.phone_number, challengeCode);
event.response.privateChallengeParameters = {};
event.response.privateChallengeParameters.answer = challengeCode;
}
}
exports.handler = async (event) => {
createAuthChallenge(event);
};
And my package.json for the same
{
"name": "XYZ",
"version": "2.0.0",
"description": "Lambda function generated by Amplify",
"main": "index.js",
"license": "Apache-2.0",
"devDependencies": {
"#types/aws-lambda": "^8.10.92"
},
"dependencies": {
"crypto-secure-random-digit": "^1.0.9"
}
}
I can't seem to find the right solution for this, can anyone help please?
Please try to replace your last line with:
exports.handler = createAuthChallenge;
If it doesn't work, can you add some other details?
Not really a useful answer, but as self-resolved.
Ultimately just used the same codes that I copied above, but redid everything from amplify delete > amplify init > amplify add auth > amplify push.
After this, no errors in simulator.
If anyone runs into similar problems, the best approach based off my experience on this, is to check the cloudwatch logs of the lambdas fired. In most cases, the logs should do a better job of pointing out where the issue is than the error messages in local. If that doesn't work, backup everything and reset amplify.

Why does glob promise return an empty string array?

I am only using typescript, ts-node, npm and path
I am simply trying to return a string array of files defined by my pattern using glob-promise (An npm that I imported which uses glob but its promise based).
I created a custom npm script to run my ts file for the terminal to display info in my package.json below
{
"name": "glob-test",
"version": "1.0.0",
"description": "A Glob Test",
"scripts": {
"build:glob": "ts-node --files globby.ts"
},
"dependencies": {
"glob-promise": "^6.0.1",
"path": "^0.12.7",
"ts-node": "^10.9.1",
"typescript": "^4.9.4"
}
}
And this below is my globby.ts file which runs the glob script
import * as path from 'path';
import glob from 'glob-promise';
const dir = path.dirname(__dirname);
const txtURL = path.resolve(dir, 'glob-test', 'folder-area', '*.txt');
glob(txtURL).then(function (cnt) {
console.log('Path: ' + txtURL);
console.log('Content: ', cnt);
});
My project directory looks like so:
I type in my terminal npm run build:glob but it returns an empty array and the path displays correctly I'm not sure what I am doing wrong. I've attempted to use path.join and path.resolve but either give the same result. It should return the joke.txt file. Anyone have any idea ?
Turns out the answer is that the path module with the glob-promise module are not playing nice in my windows environment. If I use a normal string with or without concats glob will return perfectly anything I ask.
This seems to be a bug/issue or incompatibility within the windows environment most likely. Yet to test on Linux.
e.g: Works below
import * as path from 'path';
import glob from 'glob-promise';
// const dir = path.dirname(__dirname);
const txtURL = path.resolve('folder-area', '*.txt');
const testURL = './folder-area/*.txt';
const returnTxtFiles = async () => {
const txtFiles = await glob(testURL);
console.log(txtFiles);
};
returnTxtFiles();
The above correctly returns ['joke.txt', 'file1.txt']
The other option is replace all the '/' to '' manually to any path.join("string", "string") by adding at the end .replace(/\\/g, "/")
Which is the method I went with as it took much less work adn I think is more understandable as well as it changes the original codebase the least.

"Cannot use import statement outside a module" got message when I try to mocha

I was using jest now on vue/nuxt.
And I am trying to change TDD by mocha and chai.
Installed mocha though npm i mocha --save-dev
package.json
"scripts": {
"test": "mocha"
},
test/list.spec.json
import { expect } from 'chai';
describe('test', function () {
it('should be rendered', function () {
const comp = [1, 2, 3];
expect(Math.max(...comp)).to.above(1);
});
});
Error message when I typed npm test
import { expect } from 'chai';
^^^^^^
SyntaxError: Cannot use import statement outside a module
What is problem with that ?
You cannot use the import syntax in a Node app (import { expect } from 'chai';) if your project isn't properly configured to use this newer syntax. The original Node syntax pre JS modules is const variable = require('./folder/file')
You have to set up Jest or the project you work on to work with ES6 Modules. In package.json, add "type": "module". Here's an explanation: https://www.geeksforgeeks.org/how-to-use-an-es6-import-in-node-js/

Node Environment variable ignored by testing library

I'm implementing Testing Library with Puppeteer and I was trying to use an environment variable, DEBUG_PRINT_LIMIT, to limit the length of the HTML printed to console in case of failure.
But for some reasons, the variable environment is just ignored by the library...
My project:
package.json
{
"scripts": {
"test": "jest --detectOpenHandles"
},
"devDependencies": {
"jest": "^26.6.3",
"pptr-testing-library": "^0.6.4",
"puppeteer": "^2.1.1"
}
}
main.test.js
const puppeteer = require('puppeteer')
require('pptr-testing-library/extend')
test('Should go to the forum', async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://mkpc.malahieude.net");
const $document = await page.getDocument();
const $forum = await $document.getByText("Forum");
});
Now when I run DEBUG_PRINT_LIMIT=10 npm test, the environment variable is just ignored since it prints me the whole HTML instead of just 10 characters...
I tried many things: setting the environment variable in the package.json file, or directly in the code, but nothing works, the variable is just ignored.
However if I change the code of the library (file node_modules/pptr-testing-library/dom-testing-library.js), and I replace process.env.DEBUG_PRINT_LIMIT || 7000 with process.env.DEBUG_PRINT_LIMIT || 10, then it works! So it seems that for some reason the environment variable is not passed correctly to the library.
I'm using node version 12 on a Debian machine (I think it doesn't change anything though).
Can you tell me what I'm doing wrong?
Thanks
If finally figured it out.
It's actually a bug in the library itself: https://github.com/testing-library/pptr-testing-library/issues/55

Create a TypeScript Library and use it from Node.js with ES6 and TypeScript

I want to create a TypeScript library as private npm package which can be used in Node.js (including 6.x) using ES6 with #types support and TypeScript.
The goal of the library is to extend the Request type from express and provide additional properties.
I created a new Node.js project and add this tsconfig.json:
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"sourceMap": true,
"declaration": true,
"outDir": "./dist",
"strict": true,
"types": ["mocha"]
}
}
These are the relevant parts of the package.json:
{
"name": "#myscope/my-lib",
"main": "dist",
"scripts": {
"build": "rm -rf ./dist && ./node_modules/.bin/tsc",
"test": "./node_modules/.bin/mocha test"
},
"private": true,
"dependencies": {
"joi": "11.4.0"
},
"devDependencies": {
"mocha": "^5.2.0",
"express": "^4.16.4",
"#types/express": "^4.16.1",
"#types/joi": "^14.3.0",
"#types/mocha": "^5.2.5",
"typescript": "^3.2.4"
}
}
My folder structure is this:
- dist
- src
- http
- security
- test
I created a new TypeScript file AuthenticatedRequest.ts in src/http:
import {Request} from "express";
import {UserReference} from "../security/UserReference";
export interface AuthenticatedRequest extends Request {
user: UserReference
}
src/security contains a UserReference.ts:
import {Claim} from "./Claim";
export interface UserReference {
claims: Claim[];
}
and a Claim.ts:
import {IClaim} from "./IClaim";
export class Claim implements IClaim {
type: string;
value: string;
constructor(type: string, value: string) {
this.type = type;
this.value = value;
}
}
IClaim.ts looks like this:
export interface IClaim {
type: string,
value: string
}
In test, I created AuthenticatedRequestTests.js (plain ES6, no TypeScript here to validation code completion and usage from ES6):
'use strict';
const assert = require('assert');
const Claim = require("../dist/security/Claim").Claim;
describe('req', () => {
it('should ', done => {
/** #type {AuthenticatedRequest} */
const req = {};
req.user = { claims: [new Claim('tenantId', '123')] };
assert.equal(req.user.claims[ 0 ].type, 'tenantId');
assert.equal(req.user.claims[ 0 ].value, '123');
return done();
});
});
Now I have sevaral questions:
Is this the expected TypeScript way to solve this?
Is it possible to just use require("../dist/security/Claim"); instead of require("../dist/security/Claim").Claim;?
Instead of using this jsdoc statement /** #type {AuthenticatedRequest} */ I would like to use /** #type {myLib.http.AuthenticatedRequest} */
I also created a local test project for integration and installed my library via npm link.
But instead of using
const Claim = require("#scope/my-lib/security/Claim").Claim; I have to use
const Claim = require("#scope/my-lib/dist/security/Claim").Claim;
How can I get rid of the dist folder name here?
Also, using the jsdoc comment for AuthenticatedRequest in the integration test project, I get the error that the type cannot be found:
package.json
There should be a field called types (or typings) telling your library consumers where are the type definitions for your project. If they are generated by TypeScript and saved to dist/index.d.ts, then that's the path that should be used.
"types": "./dist/index.d.ts"
There should be a field called files containing an array of files/directories that will be delivered to your end users.
Running tests
Is this the expected TypeScript way to solve this?
If you're using TypeScript to develop your library, there is no reason not to use TypeScript for your tests. There are TypeScript-compliant test runners out there (ts-jest used to be popular, and now Jest is capable of understanding TypeScript out of the box).
Is it possible to just use require("../dist/security/Claim"); instead of require("../dist/security/Claim").Claim;?
With TypeScript, a few kinds of syntax are possible. You could export Claim using a default export and do:
import Claim from "../dist/security/Claim";
or:
const Claim = require("../dist/security/Claim");
Instead of using this jsdoc statement /** #type {AuthenticatedRequest} */ I would like to use /** #type {myLib.http.AuthenticatedRequest} */.
You will need an import type. They look like that:
/**
* #type {import('path/to/AuthenticatedRequest')}
*/
const req {}
The path can be relative or absolute. If you'd like to treat the local codebase as if it were installed from npm, you can create another package.json file in your test directory and use a relative path to resolve your library module.
"dependencies": {
"my-library": "../path/to/the/root"
}
Also, using the jsdoc comment for AuthenticatedRequest in the integration test project, I get the error that the type cannot be found:
That's also solved by import types. Unless a type is not in the global scope, you need to import it before you can use it. Use import('path/to/AuthenticatedRequest') instead.
There are a few things going on. If you could create a public repository to demonstrate your problems, I'm sure it would be easier for us to help you address them.
I have an alternate answer for one part of your question. You asked
instead of using
const Claim = require("#scope/my-lib/security/Claim").Claim; I have to use
const Claim = require("#scope/my-lib/dist/security/Claim").Claim;
How can I get rid of the dist folder name here?
As Karol points out, you can use files in package.json so that when your library is published, you send the dist directory as the package root (plus package.json, README, etc). This is a great, established pattern, but has some downsides: installing the package from github: instead of NPM won't work, nor will npm link for local development.
As of very recent Node versions, you can use the exports property instead:
{
"exports": {
"./": "./dist/"
}
}
Now, require("my_lib/security/Claim") resolves to node_modules/my_lib/dist/security/Claim. It would be great if Typescript handled this automatically, but as far as I can tell you also have to specify a baseUrl and paths in your tsconfig.json, at least for now.

Resources