qa-smart-validator 1.0.0

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/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # qa-smart-validator
2
+
3
+ A small, framework-agnostic validation library for QA automation. Use it in Node.js test scripts, CI checks, or any JavaScript environment (Node.js ≥ 18). No Playwright or test-runner dependency—just validators and a safe wrapper so your automation never crashes on bad input.
4
+
5
+ ## Features
6
+
7
+ - **Email validator** – Standard format; supports gmail.com, outlook.com, yahoo.com, and custom domains (e.g. talentica.com). Rejects empty, null, and invalid formats.
8
+ - **String validator** – Ensures value is a string and enforces optional min/max length (after trim). Clear, controlled errors.
9
+ - **Phone validator** – Digits only; length 10–15. Rejects empty, null, non-digits, and out-of-range length.
10
+ - **safeValidate(fn)** – Wraps any sync validation in try/catch. Returns `{ valid: true, data }` or `{ valid: false, error }` so execution never throws.
11
+ - **ValidationError** – All validators throw this (subclass of `Error`) with `message`, `code`, and optional `field` for stable assertions and reporting.
12
+
13
+ ## Requirements
14
+
15
+ - **Node.js** ≥ 18
16
+ - **ES Modules** (`"type": "module"` or `.mjs`)
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install qa-smart-validator
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```javascript
27
+ import {
28
+ validateEmail,
29
+ validateString,
30
+ validatePhone,
31
+ safeValidate,
32
+ ValidationError,
33
+ } from 'qa-smart-validator';
34
+ ```
35
+
36
+ ## Validator examples
37
+
38
+ ### validateEmail(email)
39
+
40
+ Supports gmail.com, outlook.com, yahoo.com, and custom domains (e.g. talentica.com). Rejects empty, null, and invalid formats.
41
+
42
+ ```javascript
43
+ validateEmail('user@gmail.com'); // { valid: true, message: 'Valid email' }
44
+ validateEmail('admin@talentica.com'); // { valid: true, message: 'Valid email' }
45
+ validateEmail(''); // throws ValidationError: Email cannot be empty
46
+ validateEmail(null); // throws ValidationError: Email is required
47
+ validateEmail('not-an-email'); // throws ValidationError: Invalid email format
48
+ ```
49
+
50
+ ### validateString(value, minLength?, maxLength?)
51
+
52
+ Ensures value is a string and enforces optional min/max length (after trim).
53
+
54
+ ```javascript
55
+ validateString('hello', 1, 10); // { valid: true, value: 'hello' }
56
+ validateString('short', 10); // throws ValidationError: String length 5 is less than minimum 10
57
+ validateString(123); // throws ValidationError: Value must be a string, got number
58
+ ```
59
+
60
+ ### validatePhone(phone)
61
+
62
+ Digits only; length 10–15.
63
+
64
+ ```javascript
65
+ validatePhone('1234567890'); // { valid: true, value: '1234567890' }
66
+ validatePhone('+1234567890'); // throws ValidationError: Phone must contain only digits
67
+ validatePhone('123'); // throws ValidationError: Phone length 3 is less than minimum 10
68
+ ```
69
+
70
+ ## safeValidate example
71
+
72
+ Wraps execution in try/catch and returns a structured result. Never throws.
73
+
74
+ - **Success:** `{ valid: true, data }` – `data` is the return value of the function.
75
+ - **Failure:** `{ valid: false, error }` – `error` is the thrown error message.
76
+
77
+ ```javascript
78
+ import { validateEmail, safeValidate } from 'qa-smart-validator';
79
+
80
+ const result = safeValidate(() => validateEmail('test@gmail.com'));
81
+
82
+ console.log(result);
83
+ // { valid: true, data: { valid: true, message: 'Valid email' } }
84
+
85
+ const failed = safeValidate(() => validateEmail(''));
86
+ console.log(failed);
87
+ // { valid: false, error: 'Email cannot be empty' }
88
+ ```
89
+
90
+ ## Example file
91
+
92
+ An `example.js` is included in the package. After installing, you can run it from your app directory:
93
+
94
+ ```bash
95
+ node example.js
96
+ ```
97
+
98
+ ## API summary
99
+
100
+ | Export | Description |
101
+ |-------------------|-------------|
102
+ | `validateEmail` | Validates email; throws `ValidationError` on failure. |
103
+ | `validateString` | Validates string and optional length; throws `ValidationError` on failure. |
104
+ | `validatePhone` | Validates phone (digits, 10–15); throws `ValidationError` on failure. |
105
+ | `safeValidate(fn)`| Runs `fn()` in try/catch; returns `{ valid, data }` or `{ valid, error }`. |
106
+ | `ValidationError` | Error class with `message`, `code`, `field`. |
107
+ | `EMAIL_REGEX` | RegExp for email (advanced use). |
108
+ | `DIGITS_ONLY` | RegExp for digits (advanced use). |
109
+ | `PHONE_MIN_LENGTH` / `PHONE_MAX_LENGTH` | 10 and 15 (advanced use). |
110
+
111
+ ## Contributing
112
+
113
+ 1. Fork the repository.
114
+ 2. Create a branch (`git checkout -b feature/your-feature`).
115
+ 3. Run tests: `npm test`. Run lint: `npm run lint`. Format: `npm run format`.
116
+ 4. Commit your changes and push the branch.
117
+ 5. Open a Pull Request.
118
+
119
+ ## Publishing to npm
120
+
121
+ Before publishing:
122
+
123
+ 1. **Dry run** – See what will be packed and run lint/tests:
124
+ ```bash
125
+ npm run prepublishOnly
126
+ npm pack
127
+ ```
128
+ 2. **Login** (if needed):
129
+ ```bash
130
+ npm login
131
+ ```
132
+ 3. **Publish** (scoped packages use `--access public` for first publish):
133
+ ```bash
134
+ npm publish --access public
135
+ ```
136
+
137
+ Update `repository`, `bugs`, `homepage`, and `author` in `package.json` to your own repo and identity before publishing.
138
+
139
+ ## License
140
+
141
+ MIT
package/example.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Example usage of qa-smart-validator.
3
+ * Run from project root (after npm install): node example.js
4
+ */
5
+
6
+ import { validateEmail, safeValidate } from 'qa-smart-validator';
7
+
8
+ const result = safeValidate(() => validateEmail('test@gmail.com'));
9
+
10
+ console.log(result);
11
+ // Success: { valid: true, data: { valid: true, message: 'Valid email' } }
12
+ // Failure: { valid: false, error: '...' }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "qa-smart-validator",
3
+ "version": "1.0.0",
4
+ "description": "Reusable validation library for QA automation testing",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "example.js"
13
+ ],
14
+ "scripts": {
15
+ "test": "node --test \"test/*.js\"",
16
+ "lint": "eslint src",
17
+ "format": "prettier --write \"src/**/*.js\" \"test/**/*.js\" example.js",
18
+ "format:check": "prettier --check \"src/**/*.js\" \"test/**/*.js\" example.js",
19
+ "prepublishOnly": "npm run lint && npm run test"
20
+ },
21
+ "keywords": [
22
+ "qa",
23
+ "automation",
24
+ "validation",
25
+ "testing"
26
+ ],
27
+ "license": "MIT",
28
+ "author": "Sarath Sasidharan <sarathsasidharan13031997@gmail.com>",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/your-org/qa-smart-validator.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/your-org/qa-smart-validator/issues"
35
+ },
36
+ "homepage": "https://github.com/your-org/qa-smart-validator#readme",
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "sideEffects": false,
41
+ "devDependencies": {
42
+ "eslint": "^9.15.0",
43
+ "prettier": "^3.3.3"
44
+ }
45
+ }
package/src/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * qa-smart-validator – Reusable validation library for QA automation.
3
+ * @module qa-smart-validator
4
+ */
5
+
6
+ export { validateEmail, EMAIL_REGEX } from './validators/emailValidator.js';
7
+ export { validateString } from './validators/stringValidator.js';
8
+ export {
9
+ validatePhone,
10
+ DIGITS_ONLY,
11
+ PHONE_MIN_LENGTH,
12
+ PHONE_MAX_LENGTH,
13
+ } from './validators/phoneValidator.js';
14
+ export { safeValidate } from './utils/safeValidate.js';
15
+ export { ValidationError } from './utils/ValidationError.js';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Custom error for validation failures. Use in try/catch to distinguish
3
+ * validation errors and assert on stable `code` / `field`.
4
+ * @extends Error
5
+ */
6
+ export class ValidationError extends Error {
7
+ /**
8
+ * @param {string} message - Human-readable error message.
9
+ * @param {Object} [options] - Optional config.
10
+ * @param {string} [options.code] - Machine-readable code (e.g. 'EMAIL_INVALID').
11
+ * @param {string} [options.field] - Field name for form/API context.
12
+ */
13
+ constructor(message, options = {}) {
14
+ super(message);
15
+ this.name = 'ValidationError';
16
+ this.code = options.code ?? 'VALIDATION_ERROR';
17
+ this.field = options.field;
18
+ Object.setPrototypeOf(this, ValidationError.prototype);
19
+ }
20
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Shared assertion helpers for validators. Centralizes error type and messages.
3
+ * @module utils/assertions
4
+ */
5
+
6
+ import { ValidationError } from './ValidationError.js';
7
+
8
+ /**
9
+ * Ensures value is a non-null, non-undefined string.
10
+ * @param {*} value - Value to check.
11
+ * @param {string} name - Name of the field (for error messages).
12
+ * @returns {string} Trimmed string.
13
+ * @throws {ValidationError}
14
+ */
15
+ export function assertString(value, name = 'Value') {
16
+ if (value === undefined || value === null) {
17
+ throw new ValidationError(`${name} is required`, { code: 'REQUIRED' });
18
+ }
19
+ if (typeof value !== 'string') {
20
+ throw new ValidationError(
21
+ `${name} must be a string, got ${typeof value}`,
22
+ { code: 'INVALID_TYPE' }
23
+ );
24
+ }
25
+ return value.trim();
26
+ }
27
+
28
+ /**
29
+ * Ensures a trimmed string is non-empty.
30
+ * @param {string} trimmed - Already trimmed string.
31
+ * @param {string} name - Field name for error message.
32
+ * @throws {ValidationError}
33
+ */
34
+ export function assertNonEmpty(trimmed, name = 'Value') {
35
+ if (trimmed.length === 0) {
36
+ throw new ValidationError(`${name} cannot be empty`, { code: 'EMPTY' });
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Ensures a value is a valid non-negative number (for length constraints).
42
+ * @param {*} value - Value to check.
43
+ * @param {string} name - Parameter name for error message.
44
+ * @returns {number}
45
+ * @throws {ValidationError}
46
+ */
47
+ export function assertNonNegativeNumber(value, name) {
48
+ const num = Number(value);
49
+ if (value === undefined || value === null || Number.isNaN(num) || num < 0) {
50
+ throw new ValidationError(
51
+ `${name} must be a non-negative number`,
52
+ { code: 'INVALID_PARAMETER' }
53
+ );
54
+ }
55
+ return num;
56
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Safe validation wrapper for QA automation.
3
+ * Wraps a synchronous function in try/catch so execution never throws.
4
+ * @module utils/safeValidate
5
+ */
6
+
7
+ /**
8
+ * Runs a synchronous validation (or any sync function) and returns a result object.
9
+ * Never throws; use in automation when you want a stable result shape instead of exceptions.
10
+ * @param {() => *} fn - Synchronous function to run (e.g. () => validateEmail(value)). No arguments.
11
+ * @returns {{ valid: true, data: * } | { valid: false, error: string, code?: string }} Success: `{ valid: true, data }`. Failure: `{ valid: false, error, code? }` (code from ValidationError if present).
12
+ * @example
13
+ * safeValidate(() => validateEmail('user@gmail.com'));
14
+ * // { valid: true, data: { valid: true, message: 'Valid email' } }
15
+ *
16
+ * safeValidate(() => validateEmail(''));
17
+ * // { valid: false, error: 'Email cannot be empty', code: 'EMPTY' }
18
+ */
19
+ export function safeValidate(fn) {
20
+ if (typeof fn !== 'function') {
21
+ return { valid: false, error: 'safeValidate requires a function' };
22
+ }
23
+ try {
24
+ const data = fn();
25
+ return { valid: true, data };
26
+ } catch (err) {
27
+ const message = err instanceof Error ? err.message : String(err);
28
+ const result = { valid: false, error: message };
29
+ if (err?.code) result.code = err.code;
30
+ return result;
31
+ }
32
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Email validator for QA automation.
3
+ * Validates standard email format. Supports gmail.com, outlook.com, yahoo.com,
4
+ * and custom domains (e.g. talentica.com). Rejects empty, null, and invalid formats.
5
+ * @module validators/emailValidator
6
+ */
7
+
8
+ import { ValidationError } from '../utils/ValidationError.js';
9
+ import { assertString, assertNonEmpty } from '../utils/assertions.js';
10
+
11
+ /** Standard email format: local@domain.tld (supports common and custom domains) */
12
+ const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
13
+
14
+ /**
15
+ * Validates an email address.
16
+ * @param {string} email - The email string to validate.
17
+ * @returns {{ valid: true, message: string }} Success result with message.
18
+ * @throws {ValidationError} If email is empty, null, not a string, or invalid format.
19
+ * @example
20
+ * validateEmail('user@gmail.com'); // { valid: true, message: 'Valid email' }
21
+ * validateEmail('admin@talentica.com'); // { valid: true, message: 'Valid email' }
22
+ * validateEmail(''); // throws ValidationError: Email cannot be empty
23
+ * validateEmail(null); // throws ValidationError: Email is required
24
+ */
25
+ export function validateEmail(email) {
26
+ const trimmed = assertString(email, 'Email');
27
+ assertNonEmpty(trimmed, 'Email');
28
+
29
+ if (!EMAIL_REGEX.test(trimmed)) {
30
+ throw new ValidationError(`Invalid email format: "${trimmed}"`, {
31
+ code: 'EMAIL_INVALID',
32
+ field: 'email',
33
+ });
34
+ }
35
+
36
+ return { valid: true, message: 'Valid email' };
37
+ }
38
+
39
+ export { EMAIL_REGEX };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Phone validator for QA automation.
3
+ * Accepts only digits; length must be between 10 and 15 (inclusive).
4
+ * Rejects empty, null, non-string, non-digits, and out-of-range length.
5
+ * @module validators/phoneValidator
6
+ */
7
+
8
+ import { ValidationError } from '../utils/ValidationError.js';
9
+ import { assertString, assertNonEmpty } from '../utils/assertions.js';
10
+
11
+ /** Digits only (for phone validation) */
12
+ const DIGITS_ONLY = /^\d+$/;
13
+
14
+ /** Phone length bounds (inclusive) */
15
+ const PHONE_MIN_LENGTH = 10;
16
+ const PHONE_MAX_LENGTH = 15;
17
+
18
+ /**
19
+ * Validates a phone number (digits only, 10–15 characters).
20
+ * @param {string} phone - The phone string to validate.
21
+ * @returns {{ valid: true, value: string }} Success result with digit string.
22
+ * @throws {ValidationError} If phone is empty, null, non-string, contains non-digits, or length out of range.
23
+ * @example
24
+ * validatePhone('1234567890'); // { valid: true, value: '1234567890' }
25
+ * validatePhone('123'); // throws ValidationError: Phone length 3 is less than minimum 10
26
+ */
27
+ export function validatePhone(phone) {
28
+ const trimmed = assertString(phone, 'Phone');
29
+ assertNonEmpty(trimmed, 'Phone');
30
+
31
+ if (!DIGITS_ONLY.test(trimmed)) {
32
+ throw new ValidationError('Phone must contain only digits', {
33
+ code: 'PHONE_INVALID',
34
+ field: 'phone',
35
+ });
36
+ }
37
+
38
+ if (trimmed.length < PHONE_MIN_LENGTH) {
39
+ throw new ValidationError(
40
+ `Phone length ${trimmed.length} is less than minimum ${PHONE_MIN_LENGTH}`,
41
+ { code: 'PHONE_TOO_SHORT', field: 'phone' }
42
+ );
43
+ }
44
+
45
+ if (trimmed.length > PHONE_MAX_LENGTH) {
46
+ throw new ValidationError(
47
+ `Phone length ${trimmed.length} exceeds maximum ${PHONE_MAX_LENGTH}`,
48
+ { code: 'PHONE_TOO_LONG', field: 'phone' }
49
+ );
50
+ }
51
+
52
+ return { valid: true, value: trimmed };
53
+ }
54
+
55
+ export { DIGITS_ONLY, PHONE_MIN_LENGTH, PHONE_MAX_LENGTH };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * String validator for QA automation.
3
+ * Ensures value is a string and enforces optional min/max length (after trim).
4
+ * @module validators/stringValidator
5
+ */
6
+
7
+ import { ValidationError } from '../utils/ValidationError.js';
8
+ import {
9
+ assertString,
10
+ assertNonNegativeNumber,
11
+ } from '../utils/assertions.js';
12
+
13
+ /**
14
+ * Validates a string value with optional length constraints.
15
+ * Value is trimmed before length checks. Throws controlled ValidationError for invalid input.
16
+ * @param {*} value - The value to validate (must be a string).
17
+ * @param {number} [minLength] - Minimum length (inclusive). Omit for no minimum.
18
+ * @param {number} [maxLength] - Maximum length (inclusive). Omit for no maximum.
19
+ * @returns {{ valid: true, value: string }} Success result with trimmed value.
20
+ * @throws {ValidationError} If value is null/undefined, not a string, or fails length validation.
21
+ * @example
22
+ * validateString('hello', 1, 10); // { valid: true, value: 'hello' }
23
+ * validateString(123); // throws ValidationError: Value must be a string, got number
24
+ */
25
+ export function validateString(value, minLength, maxLength) {
26
+ const trimmed = assertString(value, 'Value');
27
+
28
+ if (minLength !== undefined && minLength !== null) {
29
+ const min = assertNonNegativeNumber(minLength, 'minLength');
30
+ if (trimmed.length < min) {
31
+ throw new ValidationError(
32
+ `String length ${trimmed.length} is less than minimum ${min}`,
33
+ { code: 'STRING_TOO_SHORT', field: 'value' }
34
+ );
35
+ }
36
+ }
37
+
38
+ if (maxLength !== undefined && maxLength !== null) {
39
+ const max = assertNonNegativeNumber(maxLength, 'maxLength');
40
+ if (trimmed.length > max) {
41
+ throw new ValidationError(
42
+ `String length ${trimmed.length} exceeds maximum ${max}`,
43
+ { code: 'STRING_TOO_LONG', field: 'value' }
44
+ );
45
+ }
46
+ }
47
+
48
+ if (
49
+ minLength != null &&
50
+ maxLength != null &&
51
+ Number(minLength) > Number(maxLength)
52
+ ) {
53
+ throw new ValidationError('minLength cannot be greater than maxLength', {
54
+ code: 'INVALID_PARAMETER',
55
+ });
56
+ }
57
+
58
+ return { valid: true, value: trimmed };
59
+ }