Repository: restqa/restqa (js)

Issue:
🐞 [Bug]: Conflict ESM <> CJS for custom step definitions.
### Contact Details

_No response_

### What happened?

Currently the RestQA is written is CJS, but when RestQA has to test a project in ESM while RestQA is trying to load the custom step definition file: `tests/steps.js` an error will occurred...


### Relevant log output

```shell
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/olivierodo/WORKS/restqa/restqa/packages/screenshot/tests/steps.js from /Users/olivierodo/WORKS/restqa/restqa/packages/cli/dist/src/setup.js not supported.
steps.js is treated as an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which declares all .js files in that package scope as ES modules.
Instead rename steps.js to end in .cjs, change the requiring code to use dynamic import() which is available in all CommonJS modules, or change "type": "module" to "type": "commonjs" in /Users/olivierodo/WORKS/restqa/restqa/packages/screenshot/package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).

    at sR.exports (/Users/olivierodo/WORKS/restqa/restqa/packages/cli/dist/src/setup.js:193:23164)
    at Object.<anonymous> (/Users/olivierodo/WORKS/restqa/restqa/packages/cli/dist/src/setup.js:193:24342)
    at /Users/olivierodo/WORKS/restqa/restqa/node_modules/.pnpm/@cucumber+cucumber@7.3.2/node_modules/@cucumber/cucumber/lib/cli/index.js:122:17
    at Array.forEach (<anonymous>)
    at Cli.getSupportCodeLibrary (/Users/olivierodo/WORKS/restqa/restqa/node_modules/.pnpm/@cucumber+cucumber@7.3.2/node_modules/@cucumber/cucumber/lib/cli/index.js:120:26)
    at Cli.run (/Users/olivierodo/WORKS/restqa/restqa/node_modules/.pnpm/@cucumber+cucumber@7.3.2/node_modules/@cucumber/cucumber/lib/cli/index.js:145:41)
    at async IC.parseAsync (/Users/olivierodo/WORKS/restqa/restqa/packages/cli/dist/bin/restqa:168:3909)
codepath: /Users/olivierodo/WORKS/restqa/restqa/packages/cli/dist/src/setup.js
```


### 🙏 Would you be willing to submit a PR?

Yes

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct

Pull request description:
fix: .cjs file for custom step definition
## Change description

> use the `.cjs` file for custom step definition and then avoid conflict

## Type of change
- [X] Bug fix (fixes an issue)
- [ ] New feature (adds functionality)

## Related issues

Fix #302

## Checklists

### Development

- [x] Lint rules pass locally
- [x] Application changes have been tested thoroughly
- [x] Automated tests covering modified code pass

### Security

- [x] Security impact of change has been considered
- [x] Code follows project security practices and guidelines

### Code review 

- [x] Pull request has a descriptive title and context useful to a reviewer. Screenshots or screencasts are attached as necessary
- [x] Changes have been reviewed by at least one other contributor
- [x] Pull request linked to issue tracker where applicable



Patch:
diff --git a/examples/custom-step-definition/.gitignore b/examples/custom-step-definition/.gitignore
new file mode 100644
index 0000000..92a77e8
--- /dev/null
+++ b/examples/custom-step-definition/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+restqa
+tests/collections
+tests/mocks
+test.txt
+
diff --git a/examples/custom-step-definition/.restqa.yml b/examples/custom-step-definition/.restqa.yml
new file mode 100644
index 0000000..927e924
--- /dev/null
+++ b/examples/custom-step-definition/.restqa.yml
@@ -0,0 +1,9 @@
+version: 0.0.1
+metadata:
+  code: -RESTQA-EXAMPLE-FASTIFY
+  name: "@restqa/example-fastify"
+  description: A RestQA example running on fastify
+tests:
+  local:
+    port: "3012"
+    command: npm run dev
diff --git a/examples/custom-step-definition/README.md b/examples/custom-step-definition/README.md
new file mode 100644
index 0000000..421182d
--- /dev/null
+++ b/examples/custom-step-definition/README.md
@@ -0,0 +1,14 @@
+# Custom step definition
+
+## Description
+
+A simple example on how you can extend the RestQA's built-in step definition.
+
+# Use Case
+
+The endpoint `POST /create-file` is creating a file when it's getting requested, we would like to have a step definition that could assert that file has been created successfully.
+
+# Focus part
+
+* [tests/custom-steps.cjs](tests/custom-steps.cjs)
+* [tests/local/post-create-file.feature](tests/local/post-create-file.feature)
diff --git a/examples/custom-step-definition/index.js b/examples/custom-step-definition/index.js
new file mode 100644
index 0000000..f910537
--- /dev/null
+++ b/examples/custom-step-definition/index.js
@@ -0,0 +1,36 @@
+import fastify from 'fastify'
+import fs from 'fs'
+
+const { PORT = 3012 } = process.env
+
+const app = fastify({ logger: false })
+
+// Declare a route
+app.post('/create-file', async (request, reply) => {
+  fs.writeFileSync('test.txt', 'test content')
+  return { hello: 'world' }
+})
+
+// Run the server!
+const start = async () => {
+  try {
+    const opt = {
+      port: PORT,
+      host: '0.0.0.0'
+    }
+    await app.listen(opt)
+    console.log('Server running on the port %s', opt.port)
+  } catch (err) {
+    console.log(err)
+    app.log.error(err)
+    process.exit(1)
+  }
+}
+start()
+
+
+process.on('SIGTERM', () => {
+  app.close(() => {
+    console.log('server is closing')
+  })
+})
diff --git a/examples/custom-step-definition/package.json b/examples/custom-step-definition/package.json
new file mode 100644
index 0000000..3252da5
--- /dev/null
+++ b/examples/custom-step-definition/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "@restqa/example-custom-step-definition",
+  "private": "true",
+  "version": "1.0.0",
+  "type": "module",
+  "description": "A RestQA example running show how to load custom step definition",
+  "main": "index.js",
+  "scripts": {
+    "dev": "node index.js",
+    "test": "restqa run",
+    "happy": "restqa run --report"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "devDependencies": {
+    "@restqa/restqa": "workspace:*"
+  },
+  "dependencies": {
+    "fastify": "^4.10.2"
+  }
+}
diff --git a/examples/fastify/tests/steps.js b/examples/fastify/tests/custom-steps.cjs
similarity index 100%
rename from examples/fastify/tests/steps.js
rename to examples/fastify/tests/custom-steps.cjs
diff --git a/packages/cli/src/core/bootstrap.js b/packages/cli/src/core/bootstrap.js
index 354dbdb..ee4dfe0 100644
--- a/packages/cli/src/core/bootstrap.js
+++ b/packages/cli/src/core/bootstrap.js
@@ -1,10 +1,10 @@
 const Data = require("./data");
 const logger = require("../utils/logger");
-const fs = require("fs");
 const path = require("path");
 const RestQAData = require("@restqa/data");
 const CorePlugin = require("./plugin");
 const {cwd} = require("../utils/process.js");
+const CustomStep = require("../services/custom-step-definition");
 
 const Module = require("module");
 
@@ -85,15 +85,7 @@ module.exports = function (processor, options = {}) {
   }
   defineParameterType(buildParameterTypeRegexp(environment.data));
 
-  const customStepFile = path.resolve(cwd, "tests/steps.js");
-  if (fs.existsSync(customStepFile)) {
-    const customStep = require(customStepFile);
-    customStep({
-      Given: processor.Given,
-      When: processor.When,
-      Then: processor.Then
-    });
-  }
+  CustomStep.load(processor);
 
   options.config = config;
   CorePlugin(options, processor);
@@ -112,8 +104,7 @@ function getPluginModule(options, processor) {
       instance = require(name);
     } else {
       instance = Module.createRequire(
-        path.resolve(process.env.RESTQA_PROJECT_FOLDER || process.cwd(), ".") +
-          path.sep
+        path.resolve(process.env.RESTQA_PROJECT_FOLDER || cwd, ".") + path.sep
       )(name);
     }
     options.plugin = instance.name;
diff --git a/packages/cli/src/core/initialize.js b/packages/cli/src/core/initialize.js
index 526991e..90a3fc9 100644
--- a/packages/cli/src/core/initialize.js
+++ b/packages/cli/src/core/initialize.js
@@ -9,7 +9,7 @@ const Locale = require("../locales")();
 const Config = require("../config");
 const Executor = require("./executor");
 const {Ignore} = require("@restqa/core-git");
-const CustomStepTemplate = require("../templates/custom-steps.tmpl.js");
+const CustomStep = require("../services/custom-step-definition");
 
 const DEFAULT_ANSWER = {
   name: "app",
@@ -18,6 +18,8 @@ const DEFAULT_ANSWER = {
   telemetry: true
 };
 
+const DEFAULT_TEST_FOLDER = "tests";
+
 async function initialize(program = {}) {
   const {folder} = program;
 
@@ -93,8 +95,10 @@ async function initialize(program = {}) {
 
 initialize.generate = async function (options) {
   options.folder = options.folder || process.cwd();
+  options.testFolder = options.testFolder || DEFAULT_TEST_FOLDER;
 
-  const {name, description, port, command, folder, telemetry} = options;
+  const {name, description, port, command, folder, telemetry, testFolder} =
+    options;
 
   if (!name) {
     throw new ReferenceError("Please share a project name.");
@@ -138,7 +142,7 @@ initialize.generate = async function (options) {
 
     const response = await Generate({print: false}, {args: curl});
 
-    const output = "tests/local/get.feature";
+    const output = `${testFolder}/local/get.feature`;
 
     createRecursiveFolder(output, folder);
 
@@ -151,19 +155,19 @@ initialize.generate = async function (options) {
 
     fs.writeFileSync(path.resolve(folder, output), content.join("\n"));
 
-    fs.writeFileSync(
-      path.resolve(folder, "tests/steps.js"),
-      CustomStepTemplate()
-    );
+    CustomStep.createTemplate(path.resolve(folder, testFolder));
 
     const ignoreFiles = [
       "restqa",
-      "tests/mocks",
-      "tests/collections",
-      "tests/integrations",
-      "tests/performances"
+      `${testFolder}/mocks`,
+      `${testFolder}/collections`,
+      `${testFolder}/integrations`,
+      `${testFolder}/performances`
     ];
-    Ignore({files: ignoreFiles});
+    Ignore({
+      files: ignoreFiles,
+      folder
+    });
 
     logger.info("service.init.success.sample");
   } catch (err) {
diff --git a/packages/cli/src/services/custom-step-definition.js b/packages/cli/src/services/custom-step-definition.js
new file mode 100644
index 0000000..ae4ffda
--- /dev/null
+++ b/packages/cli/src/services/custom-step-definition.js
@@ -0,0 +1,53 @@
+const {cwd} = require("../utils/process.js");
+const path = require("path");
+const fs = require("fs");
+
+const FILE_NAME = "custom-steps.cjs";
+const TEMPLATE = `
+module.exports = function ({ Given, When, Then }) {
+
+  /*
+  Given ('add a custom header', function () { //Sample of a custom Given step definition
+    this.api.request.setHeader('x-custom', 12345)
+  })
+  */
+
+  /*
+  When ('erase request body', function () {  //Sample of a custom When step definition
+    this.api.setPayload({})
+  })
+  */
+
+  /*
+  Then ('status ok', function () { // Sample of a custom Then step definition 
+    if (String(this.api.response.statusCode).charAt(0) !== '2') {
+      throw new Error('The status code is not equal ok')
+    }
+  })
+  */
+}
+`.trim();
+
+function createTemplate(folder) {
+  fs.writeFileSync(path.resolve(folder, FILE_NAME), TEMPLATE);
+}
+
+function load(processor) {
+  const customStepFile = path.resolve(cwd, "tests", FILE_NAME);
+
+  if (fs.existsSync(customStepFile)) {
+    const customStep = require(customStepFile);
+    customStep({
+      Given: processor.Given,
+      When: processor.When,
+      Then: processor.Then
+    });
+  }
+}
+
+module.exports = {
+  createTemplate,
+  load,
+  CUSTOM_STEP_TEMPLATE: TEMPLATE,
+  CUSTOM_STEP_FILE_NAME: FILE_NAME
+};
diff --git a/packages/cli/src/templates/custom-steps.tmpl.js b/packages/cli/src/templates/custom-steps.tmpl.js
deleted file mode 100644
index ed673bf..0000000
--- a/packages/cli/src/templates/custom-steps.tmpl.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Sample of custom step definition
- * More information in the documentation: https://github.com/restqa/restqa/blob/master/docs/test-creation/custom-step.md
- *
- */
-
-module.exports = () => {
-  return `
-
-module.exports = function ({ Given, When, Then }) {
-
-  /*
-  Given ('add a custom header', function () { //Sample of a custom Given step definition
-    this.api.request.setHeader('x-custom', 12345)
-  })
-  */
-
-  /*
-  When ('erase request body', function () {  //Sample of a custom When step definition
-    this.api.setPayload({})
-  })
-  */
-
-  /*
-  Then ('status ok', function () { // Sample of a custom Then step definition 
-    if (String(this.api.response.statusCode).charAt(0) !== '2') {
-      throw new Error('The status code is not equal ok')
-    }
-  })
-  */
-}
-  `.trim();
-};
diff --git a/packages/core-git/src/ignore.js b/packages/core-git/src/ignore.js
index fef5438..6eb8342 100644
--- a/packages/core-git/src/ignore.js
+++ b/packages/core-git/src/ignore.js
@@ -7,7 +7,9 @@ function format(files) {
 }
 
 module.exports = function (options) {
-  let {files = [], gitignore = path.resolve(cwd, ".gitignore")} = options;
+  let {files = [], folder = cwd} = options;
+
+  const gitignore = path.resolve(folder, ".gitignore");
 
   let lines = [];
   if (!fs.existsSync(gitignore)) {
diff --git a/packages/sandbox/package.json b/packages/sandbox/package.json
index 4aff3d5..d92cade 100644
--- a/packages/sandbox/package.json
+++ b/packages/sandbox/package.json
@@ -8,7 +8,7 @@
     "start:dev": "node src/index.dev.js",
     "test": "restqa run tests",
     "test:watch": "nodemon -x \"npm test\" -e js,feature --ignore tests-generated/*",
-    "lint": "eslint src tests",
+    "lint": "eslint --ext .js,.cjs src tests",
     "lint:fix": "eslint src tests --fix",
     "format": "prettier --check src tests",
     "format:fix": "prettier --write src tests"
diff --git a/packages/sandbox/tests/steps.js b/packages/sandbox/tests/custom-steps.cjs
similarity index 100%
rename from packages/sandbox/tests/steps.js
rename to packages/sandbox/tests/custom-steps.cjs
diff --git a/packages/screenshot/tests/steps.cjs b/packages/screenshot/tests/custom-steps.cjs
similarity index 100%
rename from packages/screenshot/tests/steps.cjs
rename to packages/screenshot/tests/custom-steps.cjs
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d8a9dca..1765df1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -10,6 +10,15 @@ importers:
       concurrently: 6.5.1
       nodemon: 2.0.20
 
+  examples/custom-step-definition:
+    specifiers:
+      '@restqa/restqa': workspace:*
+      fastify: ^4.10.2
+    dependencies:
+      fastify: 4.10.2
+    devDependencies:
+      '@restqa/restqa': link:../../packages/cli
+
   examples/express:
     specifiers:
       '@restqa/restqa': workspace:*
@@ -531,7 +540,7 @@ importers:
     dependencies:
       commander: 8.3.0
       file-url: 4.0.0
-      puppeteer: 19.4.0
+      puppeteer: 19.4.1
     devDependencies:
       '@restqa/restqa': link:../cli
       eslint: 7.32.0
@@ -1432,7 +1441,7 @@ packages:
       convert-source-map: 1.9.0
       debug: 4.3.4
       gensync: 1.0.0-beta.2
-      json5: 2.2.1
+      json5: 2.2.2
       semver: 6.3.0
     transitivePeerDependencies:
       - supports-color
@@ -1924,8 +1933,8 @@ packages:
       ajv: 6.12.6
     dev: true
 
-  /@fastify/ajv-compiler/3.4.0:
-    resolution: {integrity: sha512-69JnK7Cot+ktn7LD5TikP3b7psBPX55tYpQa8WSumt8r117PCa2zwHnImfBtRWYExreJlI48hr0WZaVrTBGj7w==}
+  /@fastify/ajv-compiler/3.5.0:
+    resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==}
     dependencies:
       ajv: 8.11.2
       ajv-formats: 2.1.1
@@ -1944,8 +1953,8 @@ packages:
     resolution: {integrity: sha512-KAfcLa+CnknwVi5fWogrLXgidLic+GXnLjijXdpl8pvkvbXU5BGa37iZO9FGvsh9ZL4y+oFi5cbHBm5UOG+dmQ==}
     dev: false
 
-  /@fastify/fast-json-stringify-compiler/4.1.0:
-    resolution: {integrity: sha512-cTKBV2J9+u6VaKDhX7HepSfPSzw+F+TSd+k0wzifj4rG+4E5PjSFJCk19P8R6tr/72cuzgGd+mbB3jFT6lvAgw==}
+  /@fastify/fast-json-stringify-compiler/4.2.0:
+    resolution: {integrity: sha512-ypZynRvXA3dibfPykQN3RB5wBdEUgSGgny8Qc6k163wYPLD4mEGEDkACp+00YmqkGvIm8D/xYoHajwyEdWD/eg==}
     dependencies:
       fast-json-stringify: 5.5.0
     dev: false
@@ -1976,8 +1985,8 @@ packages:
     resolution: {integrity: sha512-FPFLbg2b06MIw1dqk2SOEMAMX3xlrreGjcui5OTxfBDtaKTmh0kioOVjT8gcfl58juawL/yF+S+gnq8aUYQx/Q==}
     dev: true
 
-  /@floating-ui/dom/1.0.10:
-    resolution: {integrity: sha512-ZRe5ZmtGYCd82zrjWnnMW8hN5H1otedLh0Ur6rRo6f0exbEe6IlkVvo1RO7tgiMvbF0Df8hkhdm50VcVYqwP6g==}
+  /@floating-ui/dom/1.0.12:
+    resolution: {integrity: sha512-HeG/wHoa2laUHlDX3xkzqlUqliAfa+zqV04LaKIwNCmCNaW2p0fQi4/Kd0LB4GdFoJ2UllLFq5gWnXAd67lg7w==}
     dependencies:
       '@floating-ui/core': 1.0.4
     dev: true
@@ -2725,8 +2734,8 @@ packages:
       '@hapi/hoek': 9.3.0
     dev: false
 
-  /@sideway/formula/3.0.0:
-    resolution: {integrity: sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==}
+  /@sideway/formula/3.0.1:
+    resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
     dev: false
 
   /@sideway/pinpoint/2.0.0:
@@ -4969,7 +4978,7 @@ packages:
     dependencies:
       '@ctrl/tinycolor': 3.5.0
       '@element-plus/icons-vue': 2.0.10_vue@3.2.45
-      '@floating-ui/dom': 1.0.10
+      '@floating-ui/dom': 1.0.12
       '@popperjs/core': /@sxzz/popperjs-es/2.11.7
       '@types/lodash': 4.14.191
       '@types/lodash-es': 4.17.6
@@ -6563,15 +6572,15 @@ packages:
   /fastify/4.10.2:
     resolution: {integrity: sha512-0T+4zI6N3S8ex0LCZi3H4FasJR4AzWw834fUkPWvV8r6GBJkLmAOfFxH8f5V29Plef24IK0QSQD/tz1Nx+1UOA==}
     dependencies:
-      '@fastify/ajv-compiler': 3.4.0
+      '@fastify/ajv-compiler': 3.5.0
       '@fastify/error': 3.2.0
-      '@fastify/fast-json-stringify-compiler': 4.1.0
+      '@fastify/fast-json-stringify-compiler': 4.2.0
       abstract-logging: 2.0.1
       avvio: 8.2.0
       content-type: 1.0.4
       find-my-way: 7.3.1
       light-my-request: 5.8.0
-      pino: 8.7.0
+      pino: 8.8.0
       process-warning: 2.1.0
       proxy-addr: 2.0.7
       rfdc: 1.3.0
@@ -9141,7 +9150,7 @@ packages:
       '@hapi/hoek': 9.3.0
       '@hapi/topo': 5.1.0
       '@sideway/address': 4.1.4
-      '@sideway/formula': 3.0.0
+      '@sideway/formula': 3.0.1
       '@sideway/pinpoint': 2.0.0
     dev: false
 
@@ -9250,8 +9259,8 @@ packages:
       minimist: 1.2.7
     dev: true
 
-  /json5/2.2.1:
-    resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==}
+  /json5/2.2.2:
+    resolution: {integrity: sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==}
     engines: {node: '>=6'}
     hasBin: true
     dev: true
@@ -10368,8 +10377,8 @@ packages:
       sonic-boom: 1.4.1
     dev: true
 
-  /pino/8.7.0:
-    resolution: {integrity: sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA==}
+  /pino/8.8.0:
+    resolution: {integrity: sha512-cF8iGYeu2ODg2gIwgAHcPrtR63ILJz3f7gkogaHC/TXVVXxZgInmNYiIpDYEwgEkxZti2Se6P2W2DxlBIZe6eQ==}
     hasBin: true
     dependencies:
       atomic-sleep: 1.0.0
@@ -10606,8 +10615,8 @@ packages:
       escape-goat: 2.1.1
     dev: false
 
-  /puppeteer-core/19.4.0:
-    resolution: {integrity: sha512-gG/jxseleZStinBn86x8r7trjcE4jcjx1hIQWOpACQhquHYMuKnrWxkzg+EDn8sN3wUtF/Ry9mtJgjM49oUOFQ==}
+  /puppeteer-core/19.4.1:
+    resolution: {integrity: sha512-JHIuqtqrUAx4jGOTxXu4ilapV2jabxtVMA/e4wwFUMvtSsqK4nVBSI+Z1SKDoz7gRy/JUIc8WzmfocCa6SIZ1w==}
     engines: {node: '>=14.1.0'}
     dependencies:
       cross-fetch: 3.1.5
@@ -10619,7 +10628,7 @@ packages:
       rimraf: 3.0.2
       tar-fs: 2.1.1
       unbzip2-stream: 1.4.3
-      ws: 8.10.0
+      ws: 8.11.0
     transitivePeerDependencies:
       - bufferutil
       - encoding
@@ -10627,17 +10636,16 @@ packages:
       - utf-8-validate
     dev: false
 
-  /puppeteer/19.4.0:
-    resolution: {integrity: sha512-sRzWEfFSZCCcFUJflGtYI2V7A6qK4Jht+2JiI2LZgn+Nv/LOZZsBDEaGl98ZrS8oEcUA5on4p2yJbE0nzHNzIg==}
+  /puppeteer/19.4.1:
+    resolution: {integrity: sha512-PCnrR13B8A+VSEDXRmrNXRZbrkF1tfsI1hKSC7vs13eNS6CUD3Y4FA8SF8/VZy+Pm1kg5AggJT2Nu3HLAtGkFg==}
     engines: {node: '>=14.1.0'}
     requiresBuild: true
     dependencies:
       cosmiconfig: 8.0.0
-      devtools-protocol: 0.0.1068969
       https-proxy-agent: 5.0.1
       progress: 2.0.3
       proxy-from-env: 1.1.0
-      puppeteer-core: 19.4.0
+      puppeteer-core: 19.4.1
     transitivePeerDependencies:
       - bufferutil
       - encoding
@@ -12021,7 +12029,7 @@ packages:
     resolution: {integrity: sha512-VgPrtLKpRgEAJsMj5Q/I/mXouC6A/7eJ/X4Nuk6o0cRPwBtznYxTCU4FodbexbzH9somBPEXYi0ZkUViUpJ21Q==}
     engines: {node: '>=6'}
     dependencies:
-      json5: 2.2.1
+      json5: 2.2.2
       minimist: 1.2.7
       strip-bom: 3.0.0
     dev: true
@@ -12769,19 +12777,6 @@ packages:
         optional: true
     dev: true
 
-  /ws/8.10.0:
-    resolution: {integrity: sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==}
-    engines: {node: '>=10.0.0'}
-    peerDependencies:
-      bufferutil: ^4.0.1
-      utf-8-validate: ^5.0.2
-    peerDependenciesMeta:
-      bufferutil:
-        optional: true
-      utf-8-validate:
-        optional: true
-    dev: false
-
   /ws/8.11.0:
     resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==}
     engines: {node: '>=10.0.0'}


Test patch:
diff --git a/docs/test-creation/custom-step.md b/docs/test-creation/custom-step.md
index 88e8907..0988323 100644
--- a/docs/test-creation/custom-step.md
+++ b/docs/test-creation/custom-step.md
@@ -3,7 +3,7 @@ id: custom-step
 title: Create your own step definition
 sidebar_label: Custom step definition
 parent: test-creation
-video: https://www.youtube.com/watch?v=nhwfPNjNOno
+video: https://www.youtube.com/watch?v=z69Bi-iSKuI
 order: 4
 ---
 
@@ -12,7 +12,7 @@ to add your own step definition :)
 
 ## 1. Create your custom step definition in a few second
 
-Create a file in the folder `tests` as `<root>/tests/steps.js`
+Create a file in the folder `tests` as `<root>/tests/custom-steps.cjs`
 
 Then add the following contents:
 
@@ -43,7 +43,7 @@ To get more detail about the **Given**, **When** and **Then** function, check th
 Find below a full example on how you can use the built-in options to manipulate the API request
 
 ```js
-// file: tests/steps.js
+// file: tests/custom-steps.cjs
 const assert = require('assert')
 
 module.exports = function ({ Given, When, Then }) {
@@ -97,7 +97,7 @@ Then ('assert the response', function () {
 RestQA also has a few options allowing to manage the data flowing within one scenario.
 
 ```js
-// file: tests/steps.js
+// file: tests/custom-steps.cjs
 const assert = require('assert')
 
 module.exports = function ({ Given, When, Then }) {
diff --git a/examples/custom-step-definition/tests/custom-steps.cjs b/examples/custom-step-definition/tests/custom-steps.cjs
new file mode 100644
index 0000000..9435048
--- /dev/null
+++ b/examples/custom-step-definition/tests/custom-steps.cjs
@@ -0,0 +1,21 @@
+const fs = require('fs')
+module.exports = function ({ Given, When, Then }) {
+
+  /*
+  Given ('add a custom header', function () { //Sample of a custom Given step definition
+    this.api.request.setHeader('x-custom', 12345)
+  })
+  */
+
+  /*
+  When ('erase request body', function () {  //Sample of a custom When step definition
+    this.api.setPayload({})
+  })
+  */
+
+  Then ('the file {string} exists', function (filename) { // Sample of a custom Then step definition 
+    if (fs.existsSync(filename) === false) {
+      throw new Error(`The file ${filename} does not exists`)
+    }
+  })
+}
diff --git a/examples/custom-step-definition/tests/local/get.feature b/examples/custom-step-definition/tests/local/get.feature
new file mode 100644
index 0000000..2479c31
--- /dev/null
+++ b/examples/custom-step-definition/tests/local/get.feature
@@ -0,0 +1,13 @@
+Feature: Example custom step definition
+
+Scenario: Check if file exists
+Given a request
+When POST "/create-file"
+Then status = 200
+  And the file "test.txt" exists
+  And the body:
+  """
+{
+  "hello": "world"
+}
+  """
diff --git a/packages/cli/src/core/bootstrap.test.js b/packages/cli/src/core/bootstrap.test.js
index 458d265..707c564 100644
--- a/packages/cli/src/core/bootstrap.test.js
+++ b/packages/cli/src/core/bootstrap.test.js
@@ -1,5 +1,6 @@
 const Plugin = require("@restqa/plugin");
 const Config = require("../config");
+const {CUSTOM_STEP_FILE_NAME} = require("../services/custom-step-definition");
 
 const jestqa = new JestQA(__filename, true);
 
@@ -488,7 +489,7 @@ module.exports = function ({ Given, When, Then }) {
   Then ('custom then step', () => {})
 }
 `;
-    jestqa.createTmpFile(contentCustomStep, "tests/steps.js");
+    jestqa.createTmpFile(contentCustomStep, `tests/${CUSTOM_STEP_FILE_NAME}`);
 
     const mockCwd = jestqa.getTmpFolder();
     jest.mock("../utils/process.js", () => {
diff --git a/packages/cli/src/core/initialize.test.js b/packages/cli/src/core/initialize.test.js
index 8facee1..ccb5d90 100644
--- a/packages/cli/src/core/initialize.test.js
+++ b/packages/cli/src/core/initialize.test.js
@@ -4,7 +4,10 @@ const fs = require("fs");
 const path = require("path");
 const os = require("os");
 const YAML = require("yaml");
-const CustomStepTemplate = require("../templates/custom-steps.tmpl.js");
+const {
+  CUSTOM_STEP_TEMPLATE,
+  CUSTOM_STEP_FILE_NAME
+} = require("../services/custom-step-definition.js");
 
 let mockGenerator;
 
@@ -297,11 +300,11 @@ Given I have an example`;
         const filenameSteps = path.resolve(
           jestqa.getTmpFolder(),
           "tests",
-          "steps.js"
+          CUSTOM_STEP_FILE_NAME
         );
         jestqa.getCurrent().files.push(filenameSteps);
         const contentSteps = fs.readFileSync(filenameSteps).toString("utf-8");
-        const expectedContentSteps = CustomStepTemplate();
+        const expectedContentSteps = CUSTOM_STEP_TEMPLATE;
         expect(contentSteps.trim()).toEqual(expectedContentSteps.trim());
       });
     });
@@ -451,6 +454,18 @@ Given I have an example`;
           value: "npm run start:dev"
         }
       ]);
+
+      const resultGitignore = fs
+        .readFileSync(path.resolve(jestqa.getTmpFolder(), ".gitignore"))
+        .toString();
+      const expectedGitignore = [
+        "restqa",
+        `tests/mocks`,
+        `tests/collections`,
+        `tests/integrations`,
+        `tests/performances`
+      ].join("\n");
+      expect(resultGitignore).toEqual(expectedGitignore);
     });
   });
 });
diff --git a/packages/core-git/tests/ignore.test.js b/packages/core-git/tests/ignore.test.js
index 30ac541..a701103 100644
--- a/packages/core-git/tests/ignore.test.js
+++ b/packages/core-git/tests/ignore.test.js
@@ -68,12 +68,12 @@ describe("# contributors", () => {
 
   test("Update .gitinore if exists and don't add the files that already in the file (pass filename)", () => {
     const initialContent = ["restqa"];
-    const {mockTestFile} = createGitignore(initialContent);
+    const {mockTestFile, mockTestPath} = createGitignore(initialContent);
 
     const {Ignore} = require("../");
     const options = {
       files: ["node_modules", "tests/", "restqa"],
-      gitignore: mockTestFile
+      folder: mockTestPath
     };
     Ignore(options);
 
diff --git a/packages/plugin-faker/tests/custom-steps.cjs b/packages/plugin-faker/tests/custom-steps.cjs
new file mode 100644
index 0000000..5103ef8
--- /dev/null
+++ b/packages/plugin-faker/tests/custom-steps.cjs
@@ -0,0 +1,9 @@
+const Faker = require('faker')
+const assert = require('assert')
+
+module.exports = function ({ Then }) {
+  Then('Check {string} is an actual value from faker', function (key) {
+    const result = this.data.get(key)
+    assert.ok(Faker.definitions.music.genre.includes(result))
+  })
+}