Automated JavaScript code quality system for the Axion framework
WebTest provides automated JavaScript code quality checking for the Axion framework using industry-standard tools:
Philosophy: Test what we own, ignore what we'll migrate to CDN.
✅ ESLint Integration - Identifies and fixes JavaScript code issues
✅ Prettier Formatting - Automatic code formatting
✅ Standard Style Guide - Follows JavaScript Standard Style with Axion customizations
✅ Selective Testing - Only tests custom Axion code, excludes third-party libraries
✅ Auto-fix Capability - Automatically fixes many linting issues
✅ Configurable Rules - Rules defined in WebTest.yaml
✅ Python Integration - Seamless integration with existing Axion Python tooling
✅ CI/CD Ready - Easy integration with continuous integration pipelines
| Requirement | Minimum Version | Download |
|---|---|---|
| Node.js | v12+ | nodejs.org |
| npm | v6+ | Included with Node.js |
| Python 3 | v3.7+ | Required for WebTest.py |
Verify Installation:
node --version # Should show v12.0.0 or higher
npm --version # Should show v6.0.0 or higher
python3 --version # Should show v3.7.0 or higher
From the project root directory:
dev-env/bin/python factory.web/WebTest.py INSTALL
What this does:
package.json with required dependencies.eslintrc.json configuration fileExpected Output:
Installing npm dependencies - This may take a few minutes...
[Node.js version] [v16.14.0]
[npm version] [8.3.1]
Creating package.json
Running npm install
added 245 packages in 32s
Created .eslintrc.json
✓ npm dependencies installed successfully
dev-env/bin/python factory.web/WebTest.py SUMMARY
Expected Output:
============================================================
WebTest - JavaScript Testing Configuration
============================================================
Files to test: 1
✓ resource.web/javascript/axion.js
Ignore patterns: 19
- *.min.js
- node_modules/**
- resource.web/javascript/ace/**
... and 14 more
npm initialized: Yes
Node.js installed: Yes
============================================================
Check JavaScript files for code quality issues:
dev-env/bin/python factory.web/WebTest.py LINT
Example Output:
=== Running JavaScript Linter ===
resource.web/javascript/axion.js
12:5 error 'GBPformatter' is never reassigned. Use 'const' instead prefer-const
16:1 error Expected indentation of 4 spaces but found 1 tab indent
199:1 error Unexpected var, use let or const instead no-var
285:5 error Strings must use singlequote quotes
474:9 warn Unexpected console statement no-console
1038:3 error 'msg' is not sanitized before DOM insertion security/detect-unsafe-regex
✖ 127 problems (84 errors, 43 warnings)
76 errors and 0 warnings potentially fixable with the --fix option
Exit Codes:
0 - No errors (success)1 - Linting errors found2 - Fatal error (configuration issue)Automatically fix fixable linting issues:
dev-env/bin/python factory.web/WebTest.py FIX
What gets auto-fixed:
var → const or letExample Output:
=== Running JavaScript Linter (Auto-fix) ===
Auto-fix enabled - Will attempt to fix issues automatically
resource.web/javascript/axion.js
✓ All files passed linting
✓ 76 errors automatically fixed
Note: Not all issues can be auto-fixed. Security issues and logic errors require manual intervention.
Format code using Prettier for consistent style:
dev-env/bin/python factory.web/WebTest.py FORMAT
What Prettier does:
Example Output:
=== Formatting JavaScript Files ===
Formatting 1 file(s)
resource.web/javascript/axion.js 82ms
✓ Files formatted successfully
Test a single JavaScript file:
dev-env/bin/python factory.web/WebTest.py CHECK resource.web/javascript/axion.js
Use case: Quick check before committing a specific file.
Display current test configuration:
dev-env/bin/python factory.web/WebTest.py SUMMARY
Shows:
Display all available commands:
dev-env/bin/python factory.web/WebTest.py
The main configuration file is factory.web/WebTest.yaml:
# Files to test (custom Axion code only)
files_to_test:
- resource.web/javascript/axion.js
- resource.web/javascript/custom-module.js
# Files to ignore (third-party libraries)
ignore_patterns:
- "*.min.js"
- "resource.web/javascript/ace/**"
- "resource.web/javascript/jquery*.js"
# ESLint rules
rules:
indent: [error, 4]
quotes: [error, single]
semi: [error, always]
# Axion-specific global functions
globals:
ax_confirm: readonly
formmodal: readonly
reportmodal: readonly
To test a new JavaScript file:
factory.web/WebTest.yamlfiles_to_test:files_to_test:
- resource.web/javascript/axion.js
- resource.web/javascript/my-new-file.js # ← Add here
- resource.web/javascript/custom-utilities.js # ← Add here
dev-env/bin/python factory.web/WebTest.py LINT
To exclude third-party libraries from testing:
Add glob patterns to ignore_patterns:
ignore_patterns:
- "*.min.js" # All minified files
- "resource.web/javascript/vendor/**" # Vendor directory
- "resource.web/javascript/third-party-lib*.js" # Specific library
- "node_modules/**" # npm dependencies
Current exclusions:
.min.js files.axion.js files (compiled/minified)Rule Severity Levels:
"off" or 0 - Rule is disabled"warn" or 1 - Rule is a warning (doesn't fail build)"error" or 2 - Rule is an error (fails build)Examples:
rules:
# Make a rule less strict
max-len:
- warn # Change from 'error' to 'warn'
- code: 150 # Increase limit from 120 to 150 characters
# Disable a rule
no-console: off # Allow console.log statements
# Add a new rule
no-magic-numbers: # Disallow magic numbers
- warn
- ignore: [0, 1, -1]
# Configure complexity
complexity:
- warn
- 15 # Warn if function complexity > 15
Full rule list: See ESLint Rules
To prevent "undefined variable" warnings for Axion functions:
Add global variables to the globals section:
globals:
# Axion utility functions
ax_confirm: readonly # Can be read but not reassigned
myGlobalVar: writable # Can be read and reassigned
MY_CONSTANT: readonly # Read-only constant
Currently defined globals:
ax_confirm, ax_prompt, ax_message, ax_dropdownformmodal, formmodalF, formdirect, forminsidereportmodal, reportrun, loadreportuuidv4, includeHTML, textRunWebTest follows the JavaScript Standard Style with customizations for Axion.
| Rule | Standard Style | Axion Custom | Reason |
|---|---|---|---|
| Indentation | 2 spaces | 4 spaces | Matches existing Axion code style |
| Quotes | Single | Single ✓ | Standard compliance |
| Semicolons | Optional | Always required | Prevents ASI bugs |
| var keyword | Avoid | Error | Use const/let instead |
| Line length | No limit | Warn at 120 | Readability |
| Complexity | No limit | Warn at 20 | Maintainability |
| console.log | Allowed | Warn | Should use logging framework |
// ❌ Bad - var is forbidden
var userName = 'John';
// ✅ Good - use const for values that don't change
const userName = 'John';
// ✅ Good - use let for values that change
let counter = 0;
counter++;
Rule: no-var: error, prefer-const: warn
// ❌ Bad - inconsistent quotes
const name = "John";
const greeting = 'Hello';
// ✅ Good - always use single quotes
const name = 'John';
const greeting = 'Hello';
Rule: quotes: [error, single]
Exception: Use double quotes to avoid escaping:
const message = "It's a nice day"; // OK - avoids escaping
// ❌ Bad - missing semicolons
const greeting = 'Hello'
console.log(greeting)
// ✅ Good - semicolons included
const greeting = 'Hello';
console.log(greeting);
Rule: semi: [error, always]
Why: Prevents Automatic Semicolon Insertion (ASI) bugs.
// ❌ Bad - inconsistent indentation
function example() {
if (true) {
console.log('wrong'); // 6 spaces
}
}
// ✅ Good - consistent 4-space indentation
function example() {
if (true) {
console.log('correct'); // 4 spaces
}
}
Rule: indent: [error, 4, { SwitchCase: 1 }]
// ❌ Bad - using == (type coercion)
if (value == '5') { }
// ✅ Good - using === (strict equality)
if (value === '5') { }
// ✅ Exception - == null checks are allowed
if (value == null) { } // Checks both null and undefined
Rule: eqeqeq: [error, always, { null: ignore }]
// ⚠️ Warn - function too complex (20+ branches)
function processData(data) {
if (data.type === 'A') {
if (data.subtype === 'A1') {
// ... many nested conditions
}
}
// ... 20+ more branches
}
// ✅ Good - refactor into smaller functions
function processData(data) {
if (data.type === 'A') {
return processTypeA(data);
}
// ... simpler logic
}
Rule: complexity: [warn, 20]
Error:
199:1 error Unexpected var, use let or const instead no-var
Bad Code:
var myVariable = 'value';
var counter = 0;
Fix:
// If the value doesn't change, use const
const myVariable = 'value';
// If the value changes, use let
let counter = 0;
counter++;
Auto-fixable: ✅ Yes (use FIX command)
Warning:
12:5 error 'GBPformatter' is never reassigned. Use 'const' instead prefer-const
Bad Code:
let config = { key: 'value' };
// config is never reassigned
Fix:
const config = { key: 'value' };
// Still mutable (properties can change), but reference is constant
Auto-fixable: ✅ Yes
Error:
285:5 error Missing semicolon semi
Bad Code:
const greeting = 'Hello'
console.log(greeting)
Fix:
const greeting = 'Hello';
console.log(greeting);
Auto-fixable: ✅ Yes
Error:
285:5 error Strings must use singlequote quotes
Bad Code:
const name = "John";
const message = "Hello";
Fix:
const name = 'John';
const message = 'Hello';
// Exception: avoid escaping
const message = "It's a beautiful day"; // OK
Auto-fixable: ✅ Yes
Error:
16:1 error Expected indentation of 4 spaces but found 1 tab indent
Bad Code:
function example() {
→ console.log('tab character'); // Tab character (→)
}
Fix:
function example() {
console.log('4 spaces'); // 4 space characters
}
Auto-fixable: ✅ Yes (use FORMAT command)
Warning:
474:9 warn Unexpected console statement no-console
Bad Code:
console.log('Debug info:', data);
Fix:
// Option 1: Use allowed methods
console.error('Error occurred:', error);
console.warn('Warning:', message);
// Option 2: Use proper logging framework
this.debug('Debug info:', data);
// Option 3: Remove console statements in production code
Auto-fixable: ❌ No (requires manual decision)
Error:
180:5 error 'formmodal' is not defined no-undef
Cause: Function is an Axion global but not declared in WebTest.yaml
Fix: Add to globals section in WebTest.yaml:
globals:
formmodal: readonly
Auto-fixable: ❌ No
Warning:
580:1 warn This line has a length of 145. Maximum allowed is 120 max-len
Bad Code:
const message = 'This is a very long string that exceeds the maximum line length of 120 characters and should be broken up into multiple lines';
Fix:
// Option 1: Break into multiple lines
const message =
'This is a very long string that exceeds the maximum line ' +
'length of 120 characters and should be broken up';
// Option 2: Use template literals
const message = `
This is a very long string that exceeds
the maximum line length
`;
// Option 3: Refactor to be more concise
Auto-fixable: ❌ No (requires manual refactoring)
Step-by-step process:
Write your JavaScript code
// resource.web/javascript/my-module.js
function myFunction() {
console.log('Hello');
}
Add file to WebTest.yaml
files_to_test:
- resource.web/javascript/my-module.js
Run linter to check for issues
dev-env/bin/python factory.web/WebTest.py LINT
Auto-fix what you can
dev-env/bin/python factory.web/WebTest.py FIX
Manually fix remaining issues
Verify all issues resolved
dev-env/bin/python factory.web/WebTest.py LINT
Commit your code
git add resource.web/javascript/my-module.js
git commit -m "feat: add my-module functionality"
Recommended approach for legacy code:
Run initial lint (expect many issues)
dev-env/bin/python factory.web/WebTest.py LINT > lint-report.txt
Auto-fix easy issues (~60% of issues)
dev-env/bin/python factory.web/WebTest.py FIX
Address critical issues first
Fix errors before warnings
Gradually improve code quality
Create baseline
# After fixing critical issues, create baseline
dev-env/bin/python factory.web/WebTest.py LINT > baseline.txt
Prevent regression
Pre-commit hook:
Create .git/hooks/pre-commit:
#!/bin/bash
# Pre-commit hook to run JavaScript linting
echo "Running JavaScript linter..."
dev-env/bin/python factory.web/WebTest.py LINT
if [ $? -ne 0 ]; then
echo "❌ Linting failed. Fix issues before committing."
echo "Run: dev-env/bin/python factory.web/WebTest.py FIX"
exit 1
fi
echo "✅ Linting passed"
exit 0
Make it executable:
chmod +x .git/hooks/pre-commit
Create .github/workflows/javascript-lint.yml:
name: JavaScript Linting
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install npm dependencies
run: dev-env/bin/python factory.web/WebTest.py INSTALL
- name: Run JavaScript linter
run: dev-env/bin/python factory.web/WebTest.py LINT
- name: Upload lint report
if: failure()
uses: actions/upload-artifact@v3
with:
name: lint-report
path: lint-report.txt
Create .gitlab-ci.yml:
javascript-lint:
stage: test
image: node:16
before_script:
- apt-get update && apt-get install -y python3
- dev-env/bin/python factory.web/WebTest.py INSTALL
script:
- dev-env/bin/python factory.web/WebTest.py LINT
artifacts:
when: on_failure
paths:
- lint-report.txt
expire_in: 1 week
pipeline {
agent any
stages {
stage('Setup') {
steps {
sh 'dev-env/bin/python factory.web/WebTest.py INSTALL'
}
}
stage('Lint') {
steps {
sh 'dev-env/bin/python factory.web/WebTest.py LINT'
}
}
}
post {
failure {
archiveArtifacts artifacts: 'lint-report.txt'
}
}
}
Error Message:
Node.js or npm not found. Please install Node.js first.
Download: https://nodejs.org/
Solution:
node --version
npm --version
Linux:
# Ubuntu/Debian
sudo apt update
sudo apt install nodejs npm
# CentOS/RHEL
sudo yum install nodejs npm
macOS:
# Using Homebrew
brew install node
Error Message:
npm dependencies not installed - Run INSTALL first
Solution:
dev-env/bin/python factory.web/WebTest.py INSTALL
If installation fails:
# Clear npm cache
npm cache clean --force
# Delete existing node_modules
rm -rf node_modules package-lock.json
# Retry installation
dev-env/bin/python factory.web/WebTest.py INSTALL
Scenario: Running LINT shows 100+ errors
Solution:
Start with auto-fix:
dev-env/bin/python factory.web/WebTest.py FIX
Focus on critical issues:
Work incrementally:
# Fix one function at a time
# Re-run linter after each fix
dev-env/bin/python factory.web/WebTest.py LINT
Temporarily adjust rules (if needed):
# In WebTest.yaml, make rules less strict temporarily
rules:
max-len: off # Disable temporarily
complexity: off # Disable temporarily
Error:
180:5 error 'formmodal' is not defined no-undef
Cause: Global function not declared in WebTest.yaml
Solution: Add to globals section:
globals:
formmodal: readonly
myCustomFunction: readonly
MY_GLOBAL_VAR: writable
Error:
npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /usr/local/lib/node_modules
Solution:
# Option 1: Use sudo (not recommended)
sudo npm install
# Option 2: Fix npm permissions (recommended)
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# Option 3: Use project-local installation (best)
# WebTest.py already does this - no action needed
Error:
Error: Cannot find module 'eslint'
Cause: Dependencies not properly installed
Solution:
# Reinstall dependencies
rm -rf node_modules package-lock.json
dev-env/bin/python factory.web/WebTest.py INSTALL
Official Documentation: https://eslint.org/docs/latest/
What is ESLint?
ESLint is a static code analysis tool for identifying problematic patterns in JavaScript code. It's highly configurable and can enforce code quality rules, catch bugs, and maintain consistent code style across a project.
Key Features:
ESLint in Axion:
.eslintrc.json (auto-generated by WebTest)WebTest.yamlnpx eslint <file>Useful ESLint Documentation:
Official Documentation: https://standardjs.com/
What is Standard Style?
JavaScript Standard Style is an opinionated JavaScript style guide with automatic code formatting. It requires no configuration and enforces consistent code style with minimal setup.
Core Rules:
if (condition))function name (params))=== instead of ==Axion Customizations:
| Standard Rule | Axion Override | Reason |
|---|---|---|
| 2 space indent | 4 space indent | Match existing code |
| No semicolons | Always semicolons | Prevent ASI bugs |
Why Standard Style?
Useful Standard Style Documentation:
Official Documentation: https://prettier.io/docs/en/
What is Prettier?
Prettier is an opinionated code formatter that enforces a consistent style by parsing code and reprinting it with its own rules. It takes the maximum line length into account, wrapping code when necessary.
Key Features:
Prettier Configuration (.prettierrc):
{
"printWidth": 100, // Line wrap at 100 characters
"tabWidth": 4, // 4 spaces per indent level
"useTabs": false, // Use spaces, not tabs
"semi": true, // Add semicolons
"singleQuote": true, // Use single quotes
"trailingComma": "es5", // Trailing commas where valid in ES5
"bracketSpacing": true, // Spaces in object literals
"arrowParens": "avoid" // Omit parens when possible
}
Prettier vs ESLint:
Useful Prettier Documentation:
Official Documentation: https://docs.npmjs.com/
What is npm?
npm is the default package manager for Node.js. It's used to install, manage, and share JavaScript packages.
Key Commands:
# Install dependencies from package.json
npm install
# Install a specific package
npm install <package-name>
# Install as dev dependency
npm install --save-dev <package-name>
# Update packages
npm update
# List installed packages
npm list
# Run a script from package.json
npm run <script-name>
# Execute a package binary
npx <command>
package.json (Auto-generated by WebTest):
{
"name": "axion-javascript-tests",
"version": "1.0.0",
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write ."
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-standard": "^17.1.0",
"prettier": "^3.1.1"
}
}
Useful npm Documentation:
JavaScript Language:
Best Practices:
Security:
Testing:
Always run the linter before committing code:
# Check for issues
dev-env/bin/python factory.web/WebTest.py LINT
# Fix auto-fixable issues
dev-env/bin/python factory.web/WebTest.py FIX
# Commit
git add .
git commit -m "Your commit message"
Why?
Most style issues can be auto-fixed:
# Instead of manually fixing 100 indentation issues
dev-env/bin/python factory.web/WebTest.py FIX
Auto-fixable issues (~60-70%):
Not auto-fixable (~30-40%):
Add new files immediately:
# When creating new JavaScript file
files_to_test:
- resource.web/javascript/axion.js
- resource.web/javascript/new-feature.js # ← Add immediately
Update globals when adding new functions:
globals:
myNewGlobalFunction: readonly # ← Add when creating global
Why?
Always add comments explaining globals:
globals:
# Form handling functions
formmodal: readonly # Opens form in modal dialog
formdirect: readonly # Navigates directly to form
# Report functions
reportmodal: readonly # Loads report in modal
# Custom utilities
uuidv4: readonly # Generates UUID v4
Why?
Priority order:
Errors (must fix)
Warnings (should fix)
Info (nice to fix)
Example workflow:
# First pass: fix errors only
dev-env/bin/python factory.web/WebTest.py LINT | grep "error"
# Second pass: fix warnings
dev-env/bin/python factory.web/WebTest.py LINT | grep "warn"
Keep npm packages up to date:
# Check for outdated packages
npm outdated
# Update packages
npm update
# Or use npm-check-updates
npx npm-check-updates -u
npm install
Why?
Recommended frequency: Monthly
Follow the configured rules consistently:
// ✅ Good - consistent style
const userName = 'John';
const userAge = 30;
const userActive = true;
// ❌ Bad - inconsistent style
const userName = 'John';
let userAge = 30; // Using let when const would work
var userActive = true; // Using var
ESLint doesn't complain about reasonable comments:
// ✅ Good - explain complex logic
function calculateDiscount(price, userType) {
// Premium users get 20% discount, regular users get 10%
const discountRate = userType === 'premium' ? 0.2 : 0.1;
return price * (1 - discountRate);
}
// ❌ Bad - obvious comment
function add(a, b) {
// Add two numbers together
return a + b; // Not needed
}
Access ESLint and Prettier directly:
# Run ESLint on specific file
npx eslint resource.web/javascript/axion.js
# Run ESLint with custom config
npx eslint --config .eslintrc.json resource.web/javascript/axion.js
# Run ESLint and fix all auto-fixable issues
npx eslint --fix resource.web/javascript/**/*.js
# Format with Prettier
npx prettier --write resource.web/javascript/axion.js
# Check if files are formatted
npx prettier --check resource.web/javascript/axion.js
# Output JSON report
npx eslint --format json --output-file lint-report.json .
Create project-specific .eslintrc.json:
{
"extends": ["standard"],
"env": {
"browser": true,
"jquery": true
},
"globals": {
"ax_confirm": "readonly",
"formmodal": "readonly"
},
"rules": {
"indent": ["error", 4],
"quotes": ["error", "single"],
"semi": ["error", "always"],
"no-console": ["warn", { "allow": ["warn", "error"] }]
}
}
Create .prettierrc with custom settings:
{
"printWidth": 100,
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "avoid",
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "lf"
}
Create .eslintignore file:
# Third-party libraries
resource.web/javascript/ace/**
resource.web/javascript/jquery*.js
resource.web/javascript/bootstrap*.js
# Minified files
**/*.min.js
**/*.axion.js
# Build output
dist/
build/
# Dependencies
node_modules/
VS Code:
Install extensions:
Settings (.vscode/settings.json):
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"eslint.validate": ["javascript"],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
WebStorm/IntelliJ:
HTML Report:
npx eslint --format html --output-file lint-report.html resource.web/javascript/axion.js
JSON Report:
npx eslint --format json --output-file lint-report.json resource.web/javascript/axion.js
JUnit Report (for CI):
npm install --save-dev eslint-junit
npx eslint --format ./node_modules/eslint-junit --output-file junit-report.xml .
After running INSTALL, these files will exist:
| File | Purpose | In Git? |
|---|---|---|
package.json |
npm dependencies | ✓ Yes |
package-lock.json |
Dependency lock file | ✓ Yes |
node_modules/ |
Installed packages (~50MB) | ❌ No (.gitignore) |
.eslintrc.json |
ESLint configuration | ✓ Yes |
.prettierrc |
Prettier configuration | ✓ Yes |
.eslintcache |
ESLint cache | ❌ No (.gitignore) |
WebTest provides:
Key Commands:
# Install
dev-env/bin/python factory.web/WebTest.py INSTALL
# Lint
dev-env/bin/python factory.web/WebTest.py LINT
# Auto-fix
dev-env/bin/python factory.web/WebTest.py FIX
# Format
dev-env/bin/python factory.web/WebTest.py FORMAT
Configuration:
factory.web/WebTest.yaml.eslintrc.json (auto-generated).prettierrcNext Steps:
INSTALL to set up environmentLINT to see current statusFIX to auto-fix issuesFor issues or questions:
axion.todo for known issuesDocument Version: 1.0.0
Last Updated: 2025-12-20
Maintained By: Axion Development Team
(c) TechnoCore - All Rights Reserved