playwright-cucumber-steps 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.editorconfig CHANGED
@@ -11,5 +11,6 @@ trim_trailing_whitespace = true
11
11
  insert_final_newline = true
12
12
  max_line_length = 120
13
13
 
14
- [*.yml]
14
+ [*.{json,yml,feature}]
15
+ indent_style = space
15
16
  indent_size = 2
@@ -0,0 +1,116 @@
1
+ # Contributer's Guide
2
+ We welcome contributions - thanks for taking the time to contribute! Here are
3
+ some guidelines to help you get started. These are just guidelines, not rules,
4
+ so use your best judgment and feel free to propose changes to this document in
5
+ a pull request.
6
+
7
+ ## Discussion
8
+ While not absolutely mandatory, it could be good if you first open an
9
+ [issue](https://github.com/Marketionist/playwright-cucumber-steps/issues)
10
+ for any bug or feature request. This allows discussion on the proper course of
11
+ action to take before coding begins.
12
+
13
+ ## General rules
14
+ Most of the information you need to start contributing code changes can be found
15
+ [here](https://guides.github.com/activities/contributing-to-open-source/).
16
+ In short: fork, make your changes and submit a pull request (PR).
17
+
18
+ ## Code Style Guide
19
+ In case your editor does not respect `.editorconfig`, here is a summary of rules:
20
+
21
+ - spacing - use spaces not tabs
22
+ - 4 spaces for `.ts` files
23
+ - 2 spaces for `.json`, `.yml`, `.feature` and other configuration files that start with a `.`
24
+ - semicolons - mandatory
25
+ - quotes - single-quote
26
+
27
+ ### Fork
28
+ Fork the project [on Github](https://github.com/Marketionist/playwright-cucumber-steps)
29
+ and check out your copy locally:
30
+
31
+ ```shell
32
+ git clone git@github.com:Marketionist/playwright-cucumber-steps.git
33
+ cd playwright-cucumber-steps
34
+ ```
35
+
36
+ ### Create your branch
37
+ Create a feature branch and start hacking:
38
+
39
+ ```shell
40
+ git checkout -b my-feature-branch origin/main
41
+ ```
42
+
43
+ We practice HEAD-based development, which means all changes are applied
44
+ directly on top of main.
45
+
46
+ ### Commit
47
+ First make sure git knows your name and email address:
48
+
49
+ ```shell
50
+ git config --global user.name 'John Doe'
51
+ git config --global user.email 'john@example.com'
52
+ ```
53
+
54
+ **Writing good commit message is important.** A commit message should be around
55
+ 50 characters or less and contain a short description of the change and
56
+ reference issues fixed (if any). Include `Fixes #N`, where _N_ is the issue
57
+ number the commit fixes, if any.
58
+
59
+ ### Rebase
60
+ Use `git rebase` (not `git merge`) to sync your work with the core repository
61
+ from time to time:
62
+
63
+ ```shell
64
+ git remote add upstream https://github.com/Marketionist/playwright-cucumber-steps.git
65
+ git fetch upstream
66
+ git rebase upstream/main
67
+ ```
68
+
69
+ ### Install all dependencies
70
+ ```shell
71
+ npm run install:test-dependencies:chrome
72
+ ```
73
+
74
+ ### Test
75
+ New features **should have tests**. Look at other tests to see how
76
+ they should be structured.
77
+
78
+ This project makes use of code linting and e2e tests to make sure we don't break
79
+ anything. Before you submit your pull request make sure you pass all the tests:
80
+
81
+ You can run code linting with: `npm run lint`.
82
+ You can run all the e2e tests with: `npm test`.
83
+
84
+ Tests can be executed locally or remotely using Travis CI. Remote tests run is
85
+ triggered by each pull request.
86
+
87
+ ### Push
88
+ ```shell
89
+ git push origin my-feature-branch
90
+ ```
91
+
92
+ Go to https://github.com/yourusername/playwright-cucumber-steps and press the
93
+ _Pull request_ link and fill out the form.
94
+
95
+ A good PR comment message can look like this:
96
+
97
+ ```text
98
+ Explain PR normatively in one line
99
+
100
+ Details (optional):
101
+ Details of PR message are a few lines of text, explaining things
102
+ in more detail, possibly giving some background about the issue
103
+ being fixed, etc.
104
+
105
+ Fixes #143
106
+ ```
107
+
108
+ Pull requests are usually reviewed within a few days. If there are comments to
109
+ address, apply your changes in new commits (preferably
110
+ [fixups](http://git-scm.com/docs/git-commit)) and push to the same branch.
111
+
112
+ ### Integration
113
+ When code review is complete, a reviewer will take your PR and integrate it to
114
+ playwright-cucumber-steps main branch.
115
+
116
+ That's it! Thanks a lot for your contribution!
package/README.md CHANGED
@@ -1,2 +1,50 @@
1
1
  # playwright-cucumber-steps
2
2
  Cucumber steps (step definitions) written with Playwright for end-to-end (e2e) tests
3
+
4
+ [![Actions Status](https://github.com/Marketionist/playwright-cucumber-steps/workflows/Build%20and%20Test/badge.svg)](https://github.com/Marketionist/playwright-cucumber-steps/actions)
5
+ [![npm version](https://img.shields.io/npm/v/playwright-cucumber-steps.svg)](https://www.npmjs.com/package/playwright-cucumber-steps)
6
+ [![NPM License](https://img.shields.io/npm/l/playwright-cucumber-steps.svg)](https://github.com/Marketionist/playwright-cucumber-steps/blob/main/LICENSE)
7
+
8
+ ## Supported versions
9
+ <table>
10
+ <thead>
11
+ <tr>
12
+ <th><a href="https://nodejs.org/" rel="nofollow" target="_blank">Node.js</a></th>
13
+ <th><a href="https://github.com/microsoft/playwright" rel="nofollow" target="_blank">Playwright</a></th>
14
+ <th><a href="https://github.com/vitalets/playwright-bdd" rel="nofollow" target="_blank">Playwright-BDD</a></th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <tr>
19
+ <td>>=22.3.x</td>
20
+ <td>>=1.57.0</td>
21
+ <td>>=8.4.2</td>
22
+ </tr>
23
+ </tbody>
24
+ </table>
25
+
26
+ ## List of predefined steps
27
+ ### Given steps
28
+ 1. `I/user go(es) to URL "..."` - open a site (by its URL provided in "" as a
29
+ string - for example: `"https://github.com/Marketionist"`) in the current
30
+ browser window/tab.
31
+ 2. `I/user go(es) to "..."."..."` - open a site (by its URL provided in
32
+ **"page"."element"**) in the current browser window/tab.
33
+ - `I/user go(es) to ... from ...` - open a site (by its URL provided in
34
+ **element** from **page**) in the current browser window/tab.
35
+
36
+ ### Then steps
37
+ 3. `page title should be "..."` - verify that title of the current browser
38
+ window/tab equals to the text (provided in "" as a string).
39
+ 4. `page title should contain "..."` - verify that title of the current browser
40
+ window/tab contains the text (provided in "" as a string).
41
+
42
+ ## Contributing
43
+ You are welcome to contribute to this repository - please see
44
+ [CONTRIBUTING.md](https://github.com/Marketionist/playwright-cucumber-steps/blob/main/CONTRIBUTING.md)
45
+ to help you get started. It is not set in stone, so you can just create a pull
46
+ request and we will help you refine it along the way.
47
+
48
+ ## Thanks
49
+ If this package was helpful to you - please give this repository a **★ Star** on
50
+ [GitHub](https://github.com/Marketionist/playwright-cucumber-steps).
@@ -0,0 +1,12 @@
1
+ declare module 'node-testing-server' {
2
+ export let nodeTestingServer: {
3
+ config: {
4
+ hostname: string,
5
+ port: number,
6
+ logsEnabled: number,
7
+ pages: Record<string, string>,
8
+ },
9
+ start: () => Promise<void>,
10
+ stop: () => Promise<void>,
11
+ };
12
+ }
package/fixtures.ts ADDED
@@ -0,0 +1,18 @@
1
+ /* eslint @typescript-eslint/no-explicit-any: off */
2
+ /* eslint no-empty-pattern: off */
3
+
4
+ import { test as base, createBdd } from 'playwright-bdd';
5
+
6
+ interface Fixtures {
7
+ ctx: Record<string, any>
8
+ }
9
+
10
+ export const test = base.extend<Fixtures>({
11
+ ctx: async ({}, use) => {
12
+ const ctx = {};
13
+
14
+ await use(ctx);
15
+ },
16
+ });
17
+
18
+ export const { Given, When, Then, } = createBdd(test);
package/index.ts ADDED
@@ -0,0 +1,33 @@
1
+ /* eslint new-cap: off */ // Disable rule for Given, When, Then
2
+
3
+ // #############################################################################
4
+
5
+ import { expect } from '@playwright/test';
6
+ import { Given, When, Then } from './fixtures.ts';
7
+ import { pageObjects } from './utils/get-page-objects.ts';
8
+
9
+ // #### Given steps ############################################################
10
+
11
+ Given('I/user go(es) to URL {string}', async ({ page, }, url: string) => {
12
+ await page.goto(url);
13
+ });
14
+
15
+ Given('I/user go(es) to {string}.{string}', async ({ page, }, pageObject: string, element: string) => {
16
+ await page.goto(pageObjects[pageObject][element]);
17
+ });
18
+
19
+ Given('I/user go(es) to {word} from {word}( page)', async ({ page, }, element: string, pageObject: string) => {
20
+ await page.goto(pageObjects[pageObject][element]);
21
+ });
22
+
23
+ // #### Then steps #############################################################
24
+
25
+ Then('page title should be {string}', async ({ page, }, text: string) => {
26
+ await expect(page).toHaveTitle(text);
27
+ });
28
+
29
+ Then('page title should contain {string}', async ({ page, }, text: string) => {
30
+ const regularExpression = new RegExp(`^.*${text}.*$`, 'g');
31
+
32
+ await expect(page).toHaveTitle(regularExpression);
33
+ });
package/package.json CHANGED
@@ -1,21 +1,27 @@
1
1
  {
2
2
  "name": "playwright-cucumber-steps",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Cucumber steps (step definitions) written with Playwright for end-to-end (e2e) tests",
5
5
  "main": "index.js",
6
6
  "engines": {
7
- "node": ">=8.x.x"
7
+ "node": ">=22.3.x"
8
8
  },
9
+ "type": "module",
9
10
  "scripts": {
10
- "install-all": "npm install && npm install cucumber@6.0.5 playwright --no-save",
11
- "test": "",
11
+ "install:test-dependencies:firefox": "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=true npm install && npx playwright install firefox",
12
+ "install:test-dependencies:chrome": "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=true npm install && npx playwright install chrome",
13
+ "install:test-dependencies:all": "npm install && npx playwright install",
14
+ "lint": "node ./node_modules/.bin/eslint *.ts --ext .ts,.tsx .",
15
+ "prepare": "husky",
16
+ "start:test-server": "node tests/testing-server.ts",
17
+ "test": "npx bddgen && npx playwright test",
12
18
  "patch": "npm version patch -m \"Bump up package version to %s\" && git push && git push origin --tags && npm publish",
13
19
  "minor": "npm version minor -m \"Bump up package version to %s\" && git push && git push origin --tags && npm publish",
14
20
  "major": "npm version major -m \"Bump up package version to %s\" && git push && git push origin --tags && npm publish"
15
21
  },
16
22
  "repository": {
17
23
  "type": "git",
18
- "url": "https://github.com/Marketionist/playwright-cucumber-steps"
24
+ "url": "git+https://github.com/Marketionist/playwright-cucumber-steps.git"
19
25
  },
20
26
  "keywords": [
21
27
  "playwright cucumber",
@@ -40,11 +46,20 @@
40
46
  "author": "Dmytro Shpakovskyi",
41
47
  "license": "MIT",
42
48
  "dependencies": {
43
- "js-automation-tools": "^1.0.5"
49
+ "js-automation-tools": "^3.1.3"
44
50
  },
45
51
  "peerDependencies": {
46
- "cucumber": ">=5.1.0",
47
- "playwright": ">=1.8.0"
52
+ "@playwright/test": ">=1.57.0",
53
+ "playwright-bdd": ">=8.4.2"
48
54
  },
49
- "devDependencies": {}
55
+ "devDependencies": {
56
+ "@playwright/test": "^1.58.0",
57
+ "playwright-bdd": "^8.4.2",
58
+ "@types/node": "^25.0.10",
59
+ "@typescript-eslint/eslint-plugin": "^8.46.2",
60
+ "@typescript-eslint/parser": "^8.46.2",
61
+ "eslint": "^8.57.1",
62
+ "husky": "^9.1.7",
63
+ "node-testing-server": "^1.6.1"
64
+ }
50
65
  }
@@ -0,0 +1,43 @@
1
+ import { defineConfig, devices } from '@playwright/test';
2
+ import { defineBddConfig, cucumberReporter } from 'playwright-bdd';
3
+
4
+ const testDir = defineBddConfig({
5
+ features: 'tests/features/*.feature',
6
+ steps: '*.ts',
7
+ });
8
+
9
+ export default defineConfig({
10
+ // Look for test files in the directory, relative to this configuration file
11
+ testDir,
12
+ // Each test is given 30 seconds to finish
13
+ timeout: 30000,
14
+
15
+ // Forbid test.only on CI
16
+ forbidOnly: !!process.env.CI,
17
+
18
+ // One retry for each test
19
+ retries: 1,
20
+ reporter: [
21
+ cucumberReporter('html', {
22
+ outputFile: 'cucumber-report/index.html',
23
+ externalAttachments: true,
24
+ }),
25
+ ],
26
+ use: {
27
+ ...devices['Desktop Chrome'],
28
+ channel: 'chrome', // or 'chrome-beta'
29
+ headless: true,
30
+ viewport: { width: 1920, height: 1080, },
31
+ ignoreHTTPSErrors: true,
32
+ trace: 'on',
33
+ screenshot: 'on',
34
+ video: 'on-first-retry',
35
+ },
36
+ // Run local server with test pages before starting the tests
37
+ webServer: {
38
+ command: 'npm run start:test-server',
39
+ url: 'http://localhost:8001',
40
+ stdout: 'pipe',
41
+ stderr: 'pipe',
42
+ },
43
+ });
@@ -0,0 +1,19 @@
1
+ @fast @user-steps @part1
2
+
3
+ Feature: Test "user ..." steps - part 1
4
+ As a user of Playwright
5
+ I should be able to use Cucumber
6
+ to run my e2e tests
7
+
8
+ Scenario: 'user goes to URL' should open corresponding page, 'title should contain' should verify the title
9
+ Given user goes to URL "https://www.saucedemo.com"
10
+ Then page title should be "Swag Labs"
11
+ And page title should contain "ag Lab"
12
+
13
+ Scenario: 'user goes to page' should open corresponding page
14
+ Given user goes to "test1-page"."pageTest1"
15
+ Then page title should be "Test1 Page"
16
+
17
+ Scenario: 'user goes to page' should open corresponding page (text style step)
18
+ Given user goes to pageTest1 from test1-page
19
+ Then page title should be "Test1 Page"
@@ -0,0 +1,9 @@
1
+ // #############################################################################
2
+
3
+ const test1Page = {
4
+
5
+ pageTest1: 'http://localhost:8001/test1.html',
6
+
7
+ };
8
+
9
+ export default test1Page;
@@ -0,0 +1,169 @@
1
+ // Add testing server to provide pages for tests
2
+ // import { NodeTestingServer } from './testing-server.d.ts';
3
+ import { nodeTestingServer } from 'node-testing-server';
4
+
5
+ // Settings for node testing server
6
+ nodeTestingServer.config = {
7
+ hostname: 'localhost',
8
+ port: 8001,
9
+ logsEnabled: 0,
10
+ pages: {
11
+ '/test1.html': `<title>Test1 Page</title><a id="link-test2-page" href="
12
+ http://localhost:8001/test2.html">Test2 page</a>
13
+ <style>
14
+ #block-menu {
15
+ width: 20%;
16
+ height: 20%;
17
+ z-index: 9999;
18
+ background-color: #FFD700;
19
+ }
20
+ </style>
21
+ <script>
22
+ window.onload = function () {
23
+ document.querySelector('h1').addEventListener("mouseover", function () {
24
+ document.getElementById("text-test").innerHTML = 'Test 1 sample text';
25
+ });
26
+ document.querySelector('h1').addEventListener("mouseout", function () {
27
+ document.getElementById("text-test").innerHTML = '';
28
+ });
29
+ document.querySelector('#button-menu-right-click').addEventListener("contextmenu", function () {
30
+ document.getElementById("text-test").innerHTML = '';
31
+ const blockMenuContainer = document.getElementById("block-menu-container");
32
+ const blockMenu = document.createElement('div');
33
+
34
+ blockMenu.setAttribute('id', 'block-menu');
35
+ blockMenu.innerHTML = 'Menu goes here...';
36
+ blockMenuContainer.insertBefore(blockMenu, blockMenuContainer.firstChild);
37
+ });
38
+ }
39
+ </script>
40
+ <h1>Test1 page</h1>
41
+ <p id="text-test"></p>
42
+ <p>
43
+ <label for="image">Upload image:</label>
44
+ <input type="file" name="image" accept="image/png, .jpeg, .jpg, image/gif">
45
+ <input type="submit" value="Upload">
46
+ </p>
47
+ <p id="block-menu-container">
48
+ <button id="button-menu-right-click">Right click menu</button>
49
+ </p>`,
50
+ '/test2.html': `<title>Test2 Page</title>
51
+ <script>
52
+ window.onload = function () {
53
+ document.getElementById("login").addEventListener("click", function () {
54
+ document.getElementById("block-credentials").innerHTML = document
55
+ .getElementById("input-username").value + document
56
+ .getElementById("input-password").value;
57
+ });
58
+ document.getElementById("input-colors").addEventListener("input", function () {
59
+ document.getElementById("block-input-color").innerHTML = document
60
+ .getElementById("input-colors").value;
61
+ });
62
+ document.getElementById("dropdown-colors").addEventListener("change", function () {
63
+ document.getElementById("block-dropdown-color").innerHTML = document
64
+ .getElementById("dropdown-colors").value;
65
+ });
66
+ }
67
+ </script>
68
+ <h1>Test2 page</h1>
69
+ <p>Credentials are: <span id="block-credentials"></span></p>
70
+ <form>
71
+ Sign in:<br>
72
+ <input id="input-username" type="text" name="input-username" placeholder="Username" value=""><br>
73
+ <input id="input-password" type="password" name="input-password" placeholder="Password" value=""><br>
74
+ </form>
75
+ <button id="login">Sign in</button>
76
+ <p>Typed in input color is: <span id="block-input-color"></span></p>
77
+ <form>
78
+ Colors:<br>
79
+ <input id="input-colors" type="text" value=""><br>
80
+ <input type="submit" value="Submit">
81
+ </form>
82
+ <p>Selected dropdown color is: <span id="block-dropdown-color"></span></p>
83
+ <select id="dropdown-colors" name="colors">
84
+ <option value="default color">Default color</option>
85
+ <option value="black">Black</option>
86
+ <option value="grey">Grey</option>
87
+ <option value="white">White</option>
88
+ <option value="red">Red</option>
89
+ <option value="crimson">Crimson</option>
90
+ <option value="magenta">Magenta</option>
91
+ <option value="blue">Blue</option>
92
+ <option value="aqua">Aqua</option>
93
+ <option value="cyan">Cyan</option>
94
+ <option value="indigo">Indigo</option>
95
+ <option value="green">Green</option>
96
+ <option value="yellow">Yellow</option>
97
+ <option value="Gold">Gold</option>
98
+ <option value="orange">Orange</option>
99
+ </select>`,
100
+ '/test-iframe.html': `<title>Test Page with iframe</title>
101
+ <h1>Test page with iframe</h1>
102
+ <iframe src="test1.html" id="iframe-test1" name="test iframe" width="400" height="300" align="left">
103
+ <p>Your browser does not support iframes</p>
104
+ </iframe>`,
105
+ '/test-alert.html': `<title>Test Page with alert</title>
106
+ <script>
107
+ window.onload = function () {
108
+ document.getElementById("button-launch-alert").addEventListener("click", function () {
109
+ let alertStatus;
110
+ if (confirm("Accept (OK) or Dismiss (Cancel) - press a button!") == true) {
111
+ alertStatus = "Alert was accepted!";
112
+ } else {
113
+ alertStatus = "Alert was canceled!";
114
+ }
115
+ document.getElementById("block-alert-status").innerHTML = alertStatus;
116
+ });
117
+ }
118
+ </script>
119
+ <h1>Test page with alert</h1>
120
+ <button id="button-launch-alert">Launch alert</button>
121
+ <p id="block-alert-status"></p>`,
122
+ '/test-loader.html': `<title>Test Page with loader</title>
123
+ <style>
124
+ #loader {
125
+ width: 70%;
126
+ height: 70%;
127
+ position: fixed;
128
+ z-index: 9999;
129
+ background-color: #FFD700;
130
+ }
131
+ </style>
132
+ <script>
133
+ function insertAfter(referenceNode, newNode) {
134
+ referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
135
+ }
136
+ function showLoader (idValue, timeToSpin = 5000) {
137
+ const blockLoader = document.createElement('div');
138
+
139
+ blockLoader.setAttribute('id', idValue);
140
+ document.body.insertBefore(blockLoader, document.body.firstChild);
141
+
142
+ setTimeout(function () {
143
+ document.getElementById(idValue).remove();
144
+ }, timeToSpin);
145
+ }
146
+ function showContentWithDelay (timeDelay = 5000) {
147
+ const title = document.querySelector('h1');
148
+ let blockContent = document.createElement('p');
149
+ blockContent.setAttribute('id', 'block-content');
150
+ blockContent.innerHTML = 'This is a test content on a page with loader';
151
+
152
+ setTimeout(function () {
153
+ insertAfter(title, blockContent);
154
+ }, timeDelay);
155
+ }
156
+ document.addEventListener('DOMContentLoaded', () => {
157
+ const timeout1 = 6000;
158
+ const timeout2 = 8000;
159
+
160
+ showLoader('loader', timeout1);
161
+ showContentWithDelay(timeout2);
162
+ });
163
+ </script>
164
+ <h1>Test page with loader</h1>`,
165
+ },
166
+ };
167
+
168
+ // Start node testing server
169
+ await nodeTestingServer.start();
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2021",
4
+ "module": "nodenext",
5
+ "outDir": "./dist",
6
+ "types": ["node", "@playwright/test"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "useUnknownInCatchVariables": false,
12
+ "noEmit": true,
13
+ "allowImportingTsExtensions": true,
14
+ "resolveJsonModule": true,
15
+ },
16
+ "include": [
17
+ "**/*.ts"
18
+ ],
19
+ "exclude": [
20
+ "node_modules",
21
+ "dist"
22
+ ]
23
+ }
@@ -0,0 +1,100 @@
1
+ // #############################################################################
2
+
3
+ import { readdir, stat } from 'node:fs';
4
+ import { promisify } from 'node:util';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ const spacesToIndent = 4;
12
+
13
+ const readdirP = promisify(readdir);
14
+ const statP = promisify(stat);
15
+
16
+ async function _readDirectory (
17
+ directory: string, allFiles?: string[]
18
+ ): Promise<string[]> {
19
+ const files = (await readdirP(directory)).map((filePath) => {
20
+ return path.join(directory, filePath);
21
+ });
22
+ const allFilesPaths = allFiles ?? [];
23
+
24
+ allFilesPaths.push(...files);
25
+ await Promise.all(
26
+ files.map(async (f) => {
27
+ return (await statP(f)).isDirectory() && _readDirectory(f, allFilesPaths);
28
+ })
29
+ );
30
+
31
+ return allFilesPaths;
32
+ }
33
+
34
+ async function readDirectories (directories: string[]): Promise<string[]> {
35
+ const allFilesPaths: string[] = [];
36
+
37
+ (await Promise.all(
38
+ directories.map(async (dir) => {
39
+ const files = await _readDirectory(dir);
40
+
41
+ return files;
42
+ })
43
+ )).map((value) => {
44
+ allFilesPaths.push(...value);
45
+ });
46
+
47
+ return allFilesPaths;
48
+ }
49
+
50
+ const isCalledExternally = __dirname.includes('node_modules');
51
+ const pOFolderPath = process.env.PO_FOLDER_PATH!;
52
+
53
+ const pageObjectsFolderPathes = 'PO_FOLDER_PATH' in process.env ?
54
+ pOFolderPath.replace(/\s+/g, '').split(',') :
55
+ [path.join('tests', 'page-objects'),];
56
+
57
+ const fullPageObjectsFolderPathes = isCalledExternally ?
58
+ pageObjectsFolderPathes.map((pageObjectsFolderPath) => {
59
+ return path.join(__dirname, '..', '..', '..', pageObjectsFolderPath);
60
+ }) :
61
+ pageObjectsFolderPathes.map((pageObjectsFolderPath) => {
62
+ return path.join(__dirname, '..', pageObjectsFolderPath);
63
+ });
64
+
65
+ // Require all Page Object files in directory
66
+ type PageObject = Record<string, Record<string, string>>;
67
+ const pageObjects: PageObject = {};
68
+
69
+ async function requirePageObjects () {
70
+ const allPageObjectFiles = await readDirectories(
71
+ fullPageObjectsFolderPathes);
72
+ const allRequiredPageObjects = allPageObjectFiles.filter(
73
+ (value) => {
74
+ return value.includes('.ts');
75
+ }
76
+ );
77
+
78
+ await Promise.all(
79
+ allRequiredPageObjects.map(async (file) => {
80
+ const fileName = path.basename(file, '.ts');
81
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
82
+ const fileContent: PageObject = await import(file);
83
+
84
+ pageObjects[fileName] = fileContent.default;
85
+
86
+ return file;
87
+ })
88
+ );
89
+
90
+ console.log(
91
+ '\nPage Objects from PO_FOLDER_PATH:',
92
+ `\n${JSON.stringify(pageObjects, null, spacesToIndent)}\n\n`
93
+ );
94
+
95
+ return pageObjects;
96
+ }
97
+
98
+ await requirePageObjects();
99
+
100
+ export { pageObjects };