I've been playing a little bit with Selenium for testing purposes. Here's a tiny example.

Create a package.json file manually or via. npm init. You could run the npm commands separately but why not just run them one time and let npm do the rest.

{
  "name": "selenium-tests",
  "homepage": "https://engbjerg.dk",
  "version": "1.0.0",
  "private": true,
  "description": "Run tests on [WEBSITE] with selenium",
  "dependencies": {
    "assert": "2.0.0",
    "chromedriver": "^87.0.4",
    "chrome-modheader": "^1.0.6",
    "mocha": "^8.2.1",
    "selenium-webdriver": "^4.0.0-alpha.8"
  },
  "author": "Willam <my@mail>",
  "main": "main.js",
  "devDependencies": {},
  "scripts": {
    "all": "mocha *.js --timeout 500000",
    "file": "mocha $npm_config_filename.js --timeout 100000",
    "function": "mocha $npm_config_filename.js --grep \"$npm_config_func\" --timeout 70000"
  }c
}
package.json

Write your first script

Example below hasn't been tested. But I've used it on live tests with small adjustments. Try it out! 😊

const { Builder, By, Key, until } = require('selenium-webdriver')
const assert = require('assert')
let chrome = require('selenium-webdriver/chrome');

const ENV_LOGIN_PAGE = 'https://test-app.engbjerg.dk/';

const Feature = require("./class/Feature");

let driver;
let feature;

describe('Features', function() {

    beforeEach(async function() {
            const { getExtension } = require('chrome-modheader');
            const options = new chrome.Options().addExtensions(getExtension());
            driver = await new Builder()
                .forBrowser('chrome')
                .setChromeOptions(options)
                .build();
        
            await driver.get(ENV_LOGIN_PAGE);
            
        	// Login into test/system here
        	await driver.findElement(By.name("password")).sendKeys("secret-code");
            await driver.findElement(By.name("email")).sendKeys("test@engbjerg.dk");
            

            feature = new Feature(driver, Key, until, By, assert);

	}); 
    
	afterEach(async function() {
		await driver.quit();
	}); 


    it('I am feature 1', async function() {
       // You could use methods from class Feature
        
       // Run test code
       
       // Assert check 
       feature.assertBool(check_test_data , match_test_data, "Does not match");
        
        
    });

});
Test file
/**
 * Located: /class/Feature 
 * Global test features
 *
 * @type {module.Feature}
 */
module.exports = class Feature {

	constructor(chromeDriver, seleniumKey, seleniumUntil, seleniumBy, checkAssert) {
		this.driver_ 	= chromeDriver;
		this.Key_ 		= seleniumKey;
		this.until_		= seleniumUntil;
		this.By_		= seleniumBy;
		this.assert_	= checkAssert;
	}
    
    /**
	 * Check by getAttribute
	 *
	 * @param input
	 * @param match
	 * @param message
	 * @returns {Promise<void>}
	 */
	async assertValue(input, match, message = "") {
		await this.assert_.strictEqual(await input.getAttribute('value'), match, message);
	}
        
    /**
     * Check if it's a boolean
	 *
	 * @param check Boolean
	 * @param match Boolean
	 * @param message string
	 * @returns {Promise<void>}
	 */
	async assertBool(check , match, message = "") {

		if (typeof check !== 'boolean' && typeof match !== 'boolean') {
			throw new Error('boolean is required');
		}

		await this.assert_.strictEqual(check, match, message);
	}
    
    /**
	 * Check by getAttribute
	 *
	 * @param input
	 * @param match
	 * @param message
	 * @returns {Promise<void>}
	 */
	async assertValue(input, match, message = "") {
		await this.assert_.strictEqual(await input.getAttribute('value'), match, message);
	}
    
    /**
	 * Check by getText()
	 *
	 * @param selector
	 * @param match
	 * @param message
	 * @returns {Promise<void>}
	 */
	async assertGetText(selector, match, message = "") {
		await this.assert_.strictEqual(await selector.getText(), match, message);
	}
    
    /**
	 * Force clear input fields
	 *
	 * @param element
	 * @returns {Promise<void>}
	 */
	async forceClearInput(element) {
		await this.driver_.executeScript(elt => elt.select(), element);
		await element.sendKeys(this.Key_.BACK_SPACE);
	}
}
DRY! I like to use a global class so I don't have to repeat basic test-comands. Here's an e.g.

Run and execute tests

# Test a whole file

$ npm run file --file=Features

# Test and run a single function

$ npm run function --filename=Features --func="I am feature 1"