Adding custom functions for Synpress/Cypress Project - javascript

I want to add custom functions to a synpress project. (Synpress is a wrapper around Cypress which allows interaction with Metamask). Note there is a question: Cypress custom command is not recognized when invoked but even though I read through this QA, my custom functions are not recognized.
This is my project setup.
synpress_project/
├─ cypress/
│ ├─ e2e/
│ ├─ support/
├─ package-lock.json
├─ package.json
From the answer mentioned before
All the code and referenced modules in index.js are loaded before your
test file. So you need to refer(require) commands.js in your index.js
file
I obeyed to that, inside cypress/support:
commands.js
import "#testing-library/cypress/add-commands";
// add it here, because custom functions need synpress commands as well
import "#synthetixio/synpress/support";
// add custom functions
Cypress.Commands.add("disconnectFromDappify", () => {
cy.disconnectMetamaskWalletFromDapp().should("be.true");
});
index.js
import './commands'
I know that the files are being read, since removing the line import "#synthetixio/synpress/support"; breaks the tests (metamask interaction does not work anymore). However, my function is not available
TypeError: cy.disconnectFromDappify is not a function
package.json
{
"devDependencies": {
"cypress": "^10.0.1"
},
"scripts": {
"test": "env-cmd -f .env npx synpress run -cf synpress.json"
},
"dependencies": {
"#synthetixio/synpress": "^1.2.0",
"env-cmd": "^10.1.0"
}
}
synpress.json
{
"baseUrl": "http://localhost:3000",
"userAgent": "synpress",
"retries": { "runMode": 0, "openMode": 0 },
"integrationFolder": "cypress/e2e/specs",
"screenshotsFolder": "screenshots",
"videosFolder": "videos",
"video": false,
"chromeWebSecurity": true,
"viewportWidth": 1366,
"viewportHeight": 850,
"component": {
"componentFolder": ".",
"testFiles": "**/*spec.{js,jsx,ts,tsx}"
},
"env": {
"coverage": false
},
"defaultCommandTimeout": 30000,
"pageLoadTimeout": 30000,
"requestTimeout": 30000,
"supportFile": "cypress/support/index.js"
}

Try adding a type definition for your custom command.
I would only expect the TypeError is you're using Typescript, but your file extensions say otherwise.
/// <reference types="cypress" />
declare namespace Cypress {
interface Chainable<Subject> {
disconnectFromDappify(): Chainable<any>
}
}
Cypress.Commands.add("disconnectFromDappify", () => {
cy.disconnectMetamaskWalletFromDapp().should("be.true");
});

With help of a colleague, I was able to solve it.
Although, I specified "supportFile": "cypress/support/index.js" inside the synpress.json. It could not find the custom functions.
But if I changed the way the supportFile is called, explicit instead of implicit, it works.
Add --supportFile='cypress/support/index.js' to the end of the command.
"scripts": {
"test": "env-cmd -f .env npx synpress run -cf synpress.json --supportFile='cypress/support/index.js'"
},
Additionally, remove import "#testing-library/cypress/add-commands"; from the commands.js file. (don't know why this is needed, but code breaks, if used, any hints are welcome!)

Related

How to import js module when Typescript declaration file is located in a separate directory?

Question:
When I run npm run build with the configuration below, rollup.js is unable to resolve the dependency (import) and displays the following message below. Is there any way to make rollup happy while also referencing the Typescript declaration file?
Message from rollup:
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
pdfjs-dist/types/web/ui_utils (imported by index.ts)
Here is my index.ts:
import { RendererType } from 'pdfjs-dist/types/web/ui_utils'
const renderType = RendererType.CANVAS;
My package.json:
{
"name": "myproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "rollup --config"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"#rollup/plugin-node-resolve": "^13.2.1",
"#rollup/plugin-typescript": "^8.3.2",
"pdfjs-dist": "^2.13.216",
"rollup": "^2.70.2",
"typescript": "^4.6.4"
}
}
My rollup.config.js:
import typescript from '#rollup/plugin-typescript';
import { nodeResolve } from '#rollup/plugin-node-resolve';
export default [
{
input: 'index.ts',
output: {
format: 'es',
file: 'index.js'
},
plugins: [
typescript(),
nodeResolve({ browser: true })
]
}
]
Here are the exact steps to reproduce the error above:
Create an empty folder and then run npm -y init
Run the following command:
npm install typescript pdfjs-dist rollup #rollup/plugin-node-resolve #rollup/plugin-typescript --save-dev
Add "build": "rollup --config" to your package.json
Create the rollup.config.js file shown above
Run npm run build in the terminal
More background:
Now, I should point out that the file pdfjs-dist/types/web/ui_utils is a typescript declaration file (ui_utils.d.ts). The actual js file is in pdfjs-dist/lib/web.
If I copy the typescript declaration file so that it is located in the same directory as the js file, dependency resolution works. However, since I will be writing a wrapper around pdf js, I would have to do this for every typescript declaration file which is very tedious and upgrading would also become an issue.
So another way to word the question would be how to resolve a module *.d.ts when the js file is located in another directory?
I came up with the following solution to the problem.
Create a d.ts with the following and name it the same as the module name (ui_utils.d.ts in my case)
declare module 'pdfjs-dist/lib/web/ui_utils' {
export * from 'pdfjs-dist/types/web/ui_utils'
}
Using the above, now I can reference the actual location of the module and Typescript will pick up the declarations as well.
import { RendererType } from 'pdfjs-dist/lib/web/ui_utils'
Side note: When using rollup, you may also need to use #rollup/plugin-commonjs to be able to resolve dependencies.

How to use override in package.json to update child dependencies

I am seeing a vulnarability in async and want to update it to 3.2.2
This is the dependency tree if i do npm list async
└─┬ webpack-dev-server#4.8.1
└─┬ portfinder#1.0.28
└── async#2.6.4
So looking at the npmdocs I tried to add override in package.json as follows.
{
"name": "some application",
"scripts": {...},
"dependencies": {...},
"overrides": {
"webpack-dev-server": {
"portfinder": {
"async": "3.2.2"
}
}
},
"devDependencies": {...}
}
But when I do npm install it didn't update async version to 3.2.2 and still shows older version in pacakge-lock.json.
I removed webpack-dev-server package from devDependencies but after running npm install I get empty on npm list async
└── (empty)
Any idea what am i doing wrong?
You need to use NPM version 8.3.0 OR above for "override" to work.
you may check the below github issue for more info,
https://github.com/npm/cli/issues/4232
You've got it backwards ... you specify which dependency you want to override the version of (e.g. async), then provide the version or list of parents and their versions, so it's like this:
"overrides": {
"async": "3.2.2"
},
OR if being specific:
"overrides": {
"async": {
"portfinder": "3.2.2"
}
},

jest says cannot import outside a module

I'm attempting make a few functions using the Test Driven Development (TDD)
I am writing in javascript.
checkTransparency(urlString)
maketransparent(urlString)
are two functions of mine I'm trying to test and develop which is located in a file called transcript.js.
These uses the inkscape and graphicsmagick npm. I checked checkTransparent works in some other project of mine, but I'm trying to make sure I can just copy paste this transparent.js into another project and use it elsewhere as well.
My folder structure of the project are the following :
+ node_modules
+ src
--- transparent.js
+ test
--- transparent.spec.js
+ package.json
+ package-lock.json
+ jest.config.js
I am using jest as my test framework.
The problem is when I run jest (or npm test)
I get the following:
FAIL test/transparent.spec.js
● Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
\\..............\transparent\test\transparent.spec.js:4 <FEW DETAILS OMITTED HERE DELIBERATELY>
import { checkTransparency, makeTransparent } from "../src/transparent"; // const transparent = require("../src/transparent");
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime._execModule (C:/Users/Kjeong/AppData/Local/Yarn/Data/global/node_modules/jest-runtime/build/index.js:988:58)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.862s
Ran all test suites.
my jest.config.js:
module.exports = {
testEnvironment: "node",
moduleDirectories: ["node_modules", "src", "transparent"],
moduleFileExtensions: [
"js",
"json",
"jsx",
"ts",
"tsx",
"node"
],
clearMocks: true,
}
I've tried the following exports to get this thing working:
export function checkTransparency(urlString) { ... }
export function makeTransparent(urlString) {... }
module.exports = {
checkTransparency: checkTransparency,
makeTransparent: makeTransparent,
};
In your package.json, using configuration like following could solve your problem:
{
"name": "<blah blah>",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"start": "node server.js",
"test": "node --experimental-vm-modules node_modules/.bin/jest"
},
}
If you really want to use import keyword then you probably need to follow these explanations. Otherwise why not just require ?
const { checkTransparency, makeTransparent } = require('../src/transparent')
Hope this helps :)

Make a babel 7 config take effect in a sibling directory

I am working on a project consisting of three parts: a Client, a Server and a Common directory which contains things I want to import from both the Client and the Server. Everything can use both JS and TS. (Thanks to the babel-typescript preset)
Directory structure
Here is how it looks like:
root/
├── babel.config.js
├── Common/
│ ├── helper1.ts
│ ├── helper2.ts
│ ├── helper3.js
├── Client/
│ ├── src/
│ │ └── file1.js
│ └── .babelrc.js
└── Server/
├── src/
│ └── file1.js
└── .babelrc.js
Babel config files
Here is what my root/babel.config.js looks like:
module.exports = {
presets: ["#babel/preset-typescript"],
plugins: [
["#babel/plugin-transform-for-of", { assumeArray: true }],
"#babel/plugin-syntax-dynamic-import",
"#babel/plugin-syntax-import-meta",
"#babel/plugin-proposal-class-properties",
"#babel/plugin-proposal-json-strings",
["#babel/plugin-proposal-decorators", { legacy: true }],
"#babel/plugin-proposal-function-sent",
"#babel/plugin-proposal-export-namespace-from",
"#babel/plugin-proposal-numeric-separator",
"#babel/plugin-proposal-throw-expressions",
"#babel/plugin-proposal-export-default-from",
"#babel/plugin-proposal-logical-assignment-operators",
"#babel/plugin-proposal-optional-chaining",
["#babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }],
"#babel/plugin-proposal-nullish-coalescing-operator",
"#babel/plugin-proposal-do-expressions",
"#babel/plugin-proposal-function-bind",
],
};
And here is what my Server/.babelrc.js looks like:
const moduleAlias = require("./tools/module-alias");
const rootConfig = require("../babel.config");
module.exports = {
presets: [
...rootConfig.presets,
[
"#babel/preset-env",
{
targets: {
node: "current",
},
exclude: ["transform-for-of"],
},
],
],
plugins: [
...rootConfig.plugins,
[
"babel-plugin-module-resolver",
{
root: ["."],
alias: moduleAlias.relativeAliases,
extensions: [".js", ".ts"],
},
],
],
};
I will omit the Client/.babelrc.js since it's very similar to the Server one.
Basic test files
Here is an example Common/helper3.js file:
function doubleSay(str) {
return `${str}, ${str}`;
}
function capitalize(str) {
return str[0].toUpperCase() + str.substring(1);
}
function exclaim(str) {
return `${str}!`;
}
const result = "hello" |> doubleSay |> capitalize |> exclaim;
console.log(result);
And inside Server/src/index.js I just import the file Common/helper3.js.
The error
Then, inside the Server directory, I do this:
npx babel-node src/index.js -x .ts,.js
Which prints the following error:
const result = "hello" |> doubleSay |> capitalize |> exclaim;
^
SyntaxError: Unexpected token >
I am definitely sure this error is related to my "strange" directory structure since it's fine when I put this exact file under Server/src.
The question
How can I keep this directory structure and tell Babel to use a config when it processes files within the Common directory?
I don't use Lerna or anything. I have setup special aliases that resolve $common to ../Common where needed. I know there is no issue with this since the file is properly found by Babel (otherwise I would get a "File not found" error)
Note
This babel structure is one of my attempt to fix the issue above. Originally I only had one babel.config.js inside Server and another inside Client. I thought having one at the root would solve this problem but it didn't change anything.
Edit after searching a lot more:
After taking a look at the babel code to find the config parsing, I noticed that this line : https://github.com/babel/babel/blob/8ca99b9f0938daa6a7d91df81e612a1a24b09d98/packages/babel-core/src/config/config-chain.js#L456 is called (null is returned).
I printed everything in this scope and noticed that babel automatically generates an only parameter containing the cwd. (Effectively saying that my babel.config.js doesn't affect my common directory despite being "above" is in the directory hierarchy).
I decided to try overloading it in the command line and arrived at this command:
npx babel-node src/index.js --root-mode upward -x .ts,.js --only .,../Common/ --ignore node_modules
(Added --only and --ignore)
This made me progress a bit: instead of failing to parse advanced syntax (pipeline operator) in js files, it failed on a ts failing, saying
export const accountStatus = Object.freeze({
^^^^^^
SyntaxError: Unexpected token export
What I don't understand is how it can parse the pipeline operator but not the typescript file even though both the pipeline plugin and the typescript are inside the same babel.config.js
Edit after solving this last issue:
Adding --only and --ignore made it work. The other issue was because I forgot to add the #babel/plugin-transform-modules-commonjs plugin and it was not able to resolve the import.
The slight change I did was adding ignore: ["**/node_modules"], to my root babel.config.js file and change my command to use those arguments: --root-mode upward -x .ts,.js --ignore __fake__.
Adding a random --ignore is enough to prevent babel from guessing by itself.
This is the solution I use and it works fine even though it's not very elegant.

How to fail Grunt build if JSHint fails during watch task?

This seems like a basic question but I can't figure out how to do it. This is how to do it in gulp.
I want when I save a file with a jshint error to fail the Grunt build. The output states that jshint failed but Grunt still completes successfully.
grunt.initConfig({
watch: {
js: {
files: ['/scripts/{,**}/*.js'],
tasks: ['newer:jshint:all']
}
}
})
I know there is grunt.fail but how would I use it here?
The following gist will report a jshint error via the CLI and fail to execute any subsequent build steps when saving the .js file.
You will need to adapt according to your requirements :
Directory structure:
project
│
├──package.json
│
├───scripts
│ │
│ └───test.js
│
├─── Gruntfile.js
│
└───node_modules
│
└─── ...
package.json
{
"name": "stack40031078",
"version": "0.0.1",
"description": "Answer to stack question 40031078",
"author": "RobC",
"license": "Apache-2.0",
"devDependencies": {
"grunt": "^1.0.1",
"grunt-contrib-jshint": "^1.0.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-newer": "^1.2.0"
}
}
Gruntfile.js
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// VALIDATE JS
jshint: {
// Note we're using 'src:' instead of 'all:' below.
files: {
src: './scripts/{,**}/*.js'
},
options: {
// Use your jshint config here or define them in
// a separate .jshintrc file and set the flag to:
//
// jshintrc: true
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
boss: true,
eqnull: true,
browser: true,
smarttabs: true,
globals: {}
}
},
// WATCH THE JS FILES
watch: {
js: {
files: ['./scripts/{,**}/*.js'],
// NOTE: we're not using 'newer:jshint:all' below, just 'newer:jshint'
tasks: ['newer:jshint' /* <-- Add subsequent build tasks here. E.g. ,'concat' - A registered task can also be added. E.g. 'default' */]
}
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-newer');
grunt.registerTask('default', [
]);
};
test.js
console.log('Hello World');
var test = function() {
return 'test';
};
Testing the demo gist
cd to the project directory
run $ npm install
run $ grunt watch
Open and make a simple edit to test.js, (e.g. add a new line to the end of the file), and save the change.
The CLI reports the error as follows:
Running "jshint:files" (jshint) task
./scripts/test.js
1 |console.log('Hello Universe');
^ 'console' is not defined.
>> 1 error in 1 file
Warning: Task "jshint:files" failed. Use --force to continue.
Aborted due to warnings.
Completed in 0.965s at Fri Oct 14 2016 10:22:59 GMT+0100 (BST) - Waiting...
NOTE:
Any subsequent build tasks specified in the tasks array of the watch.js object, (e.g. concat as per commented in the Gruntfile.js), will not be invoked using this gist as the jshint task fails (... and the concat task has not been defined of course!).
However, when the JavaScript file/s successfully pass the jshint task, any subsequent build tasks that are defined in the tasks array of the watch.js object will be invoked.
I hope this helps!

Categories

Resources