hardhat run with parameters - javascript

I need to run a particular ts script using hardhat from the command line but I need to specify parameters... Similar to this:
npx hardhat run --network rinkeby scripts/task-executor.ts param1 param2
Where the --network rinkeby is the parameter for the hardhat run
And param1 and param2 are parameters for the task-executor.ts script.
I couldn't find any post regarding this issue and I cannot make it work.
I also tried defining a hardhat task and added those parameters but if I try to execute it I get:
Error HH9: Error while loading Hardhat's configuration.
You probably tried to import the "hardhat" module from your config or a file imported from it.
This is not possible, as Hardhat can't be initialized while its config is being defined.
Because I need to import hre or ethers from hardhat in that particular task.
Does anybody know how to accomplish what i need ??
Thanks a lot!!

According to Hardhat:
Hardhat scripts are useful for simple things that don't take user arguments, and for integrating with external tools that aren't well suited for the Hardhat CLI, like a Node.js debugger.
For scripts that require parameters, you should use Hardhat Tasks.
You can code the task in a different file than hardhat.config.ts. Here is an example task using positional parameters in the file sampleTask.ts:
import { task } from "hardhat/config";
task("sampleTask", "A sample task with params")
.addPositionalParam("param1")
.addPositionalParam("param2")
.setAction(async (taskArgs) => {
console.log(taskArgs);
});
Remember to import it inside hardhat.config.ts:
import "./tasks/sampleTask";
Then run it with:
npx hardhat sampleTask hello world
And it should print:
{ param1: 'hello', param2: 'world' }
You can read more about named, positional and optional parameters on tasks here.
If you need to use hre or ethers, you can get hre from the second parameter of the setAction function:
task("sampleTask", "A sample task with params")
.addPositionalParam("param1")
.addPositionalParam("param2")
.setAction(async (taskArgs, hre) => {
const ethers = hre.ethers;
});

It could be useful to check the diferences between a script and a task and how to choose: Hardhat has This on documentation.

Usually it works like this:
const hre = require('hardhat');
const { ethers } = hre;

Related

Change .page URL based on environment I need to run the suite in

We have been building our automation suite using our staging environment, but are going live soon and want to be ready to tell the project where to run (staging, production).
The only difference between the sites in the environments is the URL. My question is, from start to finish, how can I set the .page URL via a CLI option?
Right now, I have created an environment config file that holds our staging and production URLS and then I call the data into my test files. This is fine for now, but I will need to create a script with an option to set the environment at runtime without having to do a manual find and replace before kicking it off.
I've looked around online and find, what I believe, to be code snippets and general instructions, but I'm not a dev at heart and go crossed eyed. If I could get an ELI5 for this, that would be awesome.
Example of what I'm doing now:
const env = require('../environment_variables.json')
fixture `blog`
.page `${env.production}`
And then I change production to staging or vice versa manually before kicking off the suite.
Since the project will run from CICD, I would like to be able to do something like this in my CLI and script:
testcafe env=production
The env value will then be set where the .page call is for every test file.
Thanks!
There are different ways of doing this. I've used environment variables successfully in this situation, so I'll share this solution since it will solve your problem.
I create config.json in the root of the project:
{
"baseUrl": {
"dev": "https://dev.com/",
"staging": "https://staging.com/",
"prod": "https://prod.com/"
}
}
Then I create two helper functions somewhere like Helpers/env.js:
import config from '../config';
function getEnv () {
return process.env.TESTCAFE_ENV;
}
function getBaseUrl () {
return config.baseUrl[getEnv()];
}
export { getEnv, getBaseUrl };
Then in my test files in Tests/:
import { getBaseUrl } from '../Helpers/env';
const baseUrl = getBaseUrl();
fixture `Test Suite`
.page(baseUrl);
And that's it. Then when I need to run tests on the dev, I execute:
$ TESTCAFE_ENV=dev testcafe
for staging:
$ TESTCAFE_ENV=staging testcafe
and for production:
$ TESTCAFE_ENV=prod testcafe
In v1.20.0 and later, TestCafe offers a way to specify the baseUrl in the test run configuration. You can use this approach along with environment variables, see the following example:
.testcaferc.js
const BASE_URL_MAP = {
dev: 'https://dev.com/',
staging: 'https://staging.com/',
prod: 'https://prod.com/'
};
module.exports = {
baseUrl: BASE_URL_MAP[process.env.TESTCAFE_ENV]
};
Alternatively, you can use different configuration files for each of the required setups using the --config-file option.

Importing ethers via Hardhat fails despite official testing documentation

According to the official testing documentation for Hardhat, ethers should be available implicitly within the global scope; however, it can optionally be required explicitly, like so:
const { ethers } = require("hardhat");
This fails for my local project.
My package manifest seems to include the correct dependencies:
{
"dependencies": {
"#nomiclabs/hardhat-ethers": "^2.0.1",
"#nomiclabs/hardhat-waffle": "^2.0.1",
"#openzeppelin/contracts": "https://github.com/OpenZeppelin/openzeppelin-contracts#v4.0.0-beta.0",
"chai": "^4.3.1",
"hardhat": "^2.0.11"
}
}
My unit tests file seems to match the worked example in the Hardhat documentation also:
const { ethers } = require("hardhat");
const { expect } = require("chai");
describe("Distributor.sol", function() {
it("Distribution should fail for non-owners", async function() {
const DistributorFactory = await ethers.getContractFactory("Distributor");
const Distributor = await Distributor.deploy();
Distributor.distribute([], []);
expect(await hardhatToken.totalSupply()).to.be.revertedWith("foobar");
});
});
Despite this, running the tests fails with:
$ yarn hardhat test
yarn run v1.22.5
$ /home/bob/dev/misc/token-distributor/node_modules/.bin/hardhat test
Distributor.sol
undefined
1) Distribution should fail for non-owners
0 passing (9ms)
1 failing
1) Distributor.sol
Distribution should fail for non-owners:
TypeError: Cannot read property 'getContractFactory' of undefined
at Context.<anonymous> (test/Distributor.js:8:49)
at processImmediate (internal/timers.js:461:21)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
How do I fix this?
Two things:
you need to install ethers separately too, as given in the instructions for hardhat-ethers, e.g.
npm install --save-dev #nomiclabs/hardhat-ethers 'ethers#^5.0.0'
Every Hardhat plugin needs to be registered in the Hardhat config file (hardhat.config.js):
require("#nomiclabs/hardhat-ethers");
There is no need to remove the explicit import in your test file, however, Hardhat docs recommend following this style:
const hre = require("hardhat");
const { ethers } = hre;
Add the require in your hardhat.config.js
require("#nomiclabs/hardhat-waffle");
And remove this line from your test file:
const { ethers } = require("hardhat");
Then, you can use ethers in your tests. Hardhat looks in the config first before running tests. If you have required a package that includes ethers you can use it in the global scope.
It still shows error, reading ethers undefined, I started the project all again with yarn hardhat and chose the first option "Create Simple Project" and it works perfectly.

Do I need two files for JS module run with node CLI?

I have a module that exports a method used in JEST test. I want to run it from command line too.
async function doRun() { /* do something */}
exports.doRun = doRun;
This works well from JEST, where I import the module and execute the method. But when I call it with node module.js, it has no effect because the method is not executed within JS body. To fix it I have to add:
doRun().then(() => console.log('finished'));
which makes the code work from CLI but it is executed too in JEST just after import.
Am I right that I need to create new file that imports the module and runs the code just for CLI?
const module = require('module.js')
doRun().then(() => console.log('finished'));
and then run node module_cli.js?
Pretty much, yeah. :-)
Either that, or use an environment variable
async function doRun() { /* do something */}
exports.doRun = doRun;
if (process.env.AUTO_RUN === "Y") {
doRun().then(() => console.log('finished'));
}
and run it like this on *nix:
AUTO_RUN=Y node module.js
...or on Windows according to this it would be:
cmd /V /C "set AUTO_RUN=Y&&node module.js"
You could also use the standard NODE_ENV environment variable. I haven't gotten deep into Jest, but it might set it to "testing" or something like that...

How to transpile on fly before running script?

Does anyone knows how to tackle following problem?
What is the best approach to resolve it?
I wanted to present the simplest example, but generally I would like to run node script that have some dependencies files that are not written in es5. This script takes argument from cli and perform some action (eg. change content of index.html file), here for simplicity we only console log some greeting.
Currently we would get an error:
SyntaxError: Unexpected token export
Is there a way to somehow transpile on fly all file dependencies to es5 and run the script?
sample folder structure:
src/welcome.js
src/greeting.js
src/... // bunch of other files
package.json
greeting.js
const name = process.argv[2];
export const sayHello = `Hello ${name}!`;
export const sayHi = `Hi ${name}!`;
welcome.js
const { sayHello } = require('./greeting');
console.log(greeting, "Nice to meet you!");
in package.json
"scripts": {
"greet": "node src/welcome.js"
}
cli
npm run greet John

react-testing-library why is toBeInTheDocument() not a function

Here is my code for a tooltip that toggles the CSS property display: block on MouseOver and on Mouse Out display: none.
it('should show and hide the message using onMouseOver and onMouseOut events respectively', () => {
const { queryByTestId, queryByText } = render(
<Tooltip id="test" message="test" />,
)
fireEvent.mouseOver(queryByTestId('tooltip'))
expect(queryByText('test')).toBeInTheDocument()
fireEvent.mouseOut(queryByTestId('tooltip'))
expect(queryByText('test')).not.toBeInTheDocument()
cleanup()
})
I keep getting the error TypeError: expect(...).toBeInTheDocument is not a function
Has anyone got any ideas why this is happening? My other tests to render and snapshot the component all work as expected. As do the queryByText and queryByTestId.
toBeInTheDocument is not part of RTL. You need to install jest-dom to enable it.
And then import it in your test files by:
import '#testing-library/jest-dom'
As mentioned by Giorgio, you need to install jest-dom. Here is what worked for me:
(I was using typescript)
npm i --save-dev #testing-library/jest-dom
Then add an import to your setupTests.ts
import '#testing-library/jest-dom/extend-expect';
Then in your jest.config.js you can load it via:
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.ts"
]
When you do npm i #testing-library/react make sure there is a setupTests.js file with the following statement in it
import '#testing-library/jest-dom/extend-expect';
Having tried all of the advice in this post and it still not working for me, I'd like to offer an alternative solution:
Install jest-dom:
npm i --save-dev #testing-library/jest-dom
Then create a setupTests.js file in the src directory (this bit is important! I had it in the root dir and this did not work...). In here, put:
import '#testing-library/jest-dom'
(or require(...) if that's your preference).
This worked for me :)
Some of the accepted answers were basically right but some may be slightly outdated:
Some references that are good for now:
https://github.com/testing-library/jest-dom
https://jestjs.io/docs/configuration
Here are the full things you need:
in the project's <rootDir> (aka where package.json and jest.config.js are), make sure you have a file called jest.config.js so that Jest can automatically pick it up for configuration. The file is in JS but is structured similarly to a package.json.
Make sure you input the following:
module.exports = {
testPathIgnorePatterns: ['<rootDir>/node_modules', '<rootDir>/dist'], // might want?
moduleNameMapper: {
'#components(.*)': '<rootDir>/src/components$1' // might want?
},
moduleDirectories: ['<rootDir>/node_modules', '<rootDir>/src'],
setupFilesAfterEnv: ['<rootDir>/src/jest-setup.ts'] // this is the KEY
// note it should be in the top level of the exported object.
};
Also, note that if you're using typescript you will need to make sure your jest-setup.ts file is compiled (so add it to src or to the list of items to compile in your tsconfig.json.
At the top of jest-setup.ts/js (or whatever you want to name this entrypoint) file: add import '#testing-library/jest-dom';.
You may also want to make sure it actually runs so put a console.log('hello, world!');. You also have the opportunity to add any global functions you'd like to have available in jest such as (global.fetch = jest.fn()).
Now you actually have to install #testing-library/jest-dom: npm i -D #testing-library/jest-dom in the console.
With those steps you should be ready to use jest-dom:
Without TS: you still need:
npm i -D #testing-library/jest-dom
Creating a jest.config.js and adding to it a minimum of: module.exports = { setupFilesAfterEnv: ['<rootDir>/[path-to-file]/jest-setup.js'] }.
Creating a [path-to-file]/jest-setup.js and adding to it: import '#testing-library/jest-dom';.
The jest-setup file is also a great place to configure tests like creating a special renderWithProvider( function or setting up global window functions.
None of the answers worked for me because I made the silly mistake of typing toBeInDocument() instead of toBeInTheDocument(). Maybe someone else did the same mistake :)
I had a hard time solving that problem so I believe it's important to note the followings if you're using CREATE REACT APP for your project:
You DO NOT need a jest.config.js file to solve this, so if you have that you can delete it.
You DO NOT need to change anything in package.json.
You HAVE TO name your jest setup file setupTests.js and have it under the src folder. It WILL NOT work if your setup file is called jest.setup.js or jest-setup.js.
install required packages
npm install --save-dev #testing-library/jest-dom eslint-plugin-jest-dom
create jest-setup.js in the root folder of your project and add
import '#testing-library/jest-dom'
in jest.config.js
setupFilesAfterEnv: ['<rootDir>/jest-setup.js']
TypeScript only, add the following to the tsconfig.json file. Also, change .js extension to .ts.
"include": ["./jest-setup.ts"]
toBeInTheDocument() and many similar functions are not part of the React-testing-library. It requires installing an additional package.
For anyone out there that like is trying to run tests in Typescript with jest and is still getting the same error even after installing #testing-library/jest-dom and following all the other answers: you probably need to install the type definitions for jest-dom (here) with:
npm i #types/testing-library__jest-dom
or
yarn add #types/testing-library__jest-dom
You need to install them as real dependencies and not as devDependency.
I was having this issue but for #testing-library/jasmine-dom rather than #testing-library/jest-dom.
The process of setup is just a tiny bit different with jasmine. You need to set up the environment in a before function in order for the matchers to be added. I think jest-dom will go ahead and add the matchers when you first import but Jasmine does not.
import { render, screen } from '#testing-library/react';
import MyComponent from './myComponent';
import JasmineDOM from '#testing-library/jasmine-dom';
describe("My Suite", function () {
beforeAll(() => {
jasmine.getEnv().addMatchers(JasmineDOM);
})
it('render my stuff', () => {
const { getByText } = render(<MyComponent />);
const ele = screen.getByText(/something/i);
expect(ele).toBeInTheDocument();
});
});
If you are using react-script then follow the below steps
Install #testing-library/jest-dom library if not done already using
npm i #testing-library/jest-dom.
Put import "#testing-library/jest-dom/extend-expect" in setUpTest.js
If you are using jest then import the library in jest.setup.js file.
the problem already was solved, but i will comment a little tip here, you don't need to create a single file called setup just for this, you just need to specify the module of the jest-dom on the setupFilesAfterEnv option in your jest configuration file.
Like this:
setupFilesAfterEnv: ['#testing-library/jest-dom/extend-expect'],
If you're using TS
You could also add a test.d.ts file to your test directory and use a triple slash directive:
///<reference types='#testing-library/jest-dom'>
Instead of doing:
expect(queryByText('test')).toBeInTheDocument()
you can find and test that it is in the document with just one line by using
let element = getByText('test');
The test will fail if the element isn't found with the getBy call.

Categories