Files
iot-dc3/dc3-web/tests/unit/validation-util.test.ts
pnoker d47d125af0 style(web): reformat frontend with IDEA code style
Apply IDE formatting across all Vue, TypeScript, SCSS and test files.
No logic changes — whitespace, quotes and brace style only.
2026-07-10 00:02:51 +08:00

135 lines
4.2 KiB
TypeScript

/*
* Copyright 2016-present the IoT DC3 original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {describe, expect, it} from 'vitest';
import {isEmail, isNull, isNum, isPhone, isUrl} from '@/utils/validationUtil';
describe('validationUtil', () => {
describe('isUrl', () => {
it.each([
['http://example.com', true],
['https://dc3.example.com/path', true],
['HTTPS://Example.COM', false], // case-sensitive http(s) prefix
['ftp://example.com', false],
['javascript:alert(1)', false],
['', false],
['just-text', false],
[null, false],
[undefined, false],
[42, false],
])('isUrl(%p) → %p', (input, expected) => {
expect(isUrl(input)).toBe(expected);
});
});
describe('isEmail', () => {
it.each([
['dc3@example.com', true],
['user.name+tag@example.co.uk', false], // '+' not allowed by current regex
['user.name@example.co.uk', true],
['a@b.cd', true],
['plain', false],
['@example.com', false],
['user@', false],
['user@example', false],
// The TLD piece is `([a-zA-Z0-9]{2,4})+$` — the trailing `+` quantifier
// means a 10-char TLD can still match as 4+4+2. Pin this current
// behaviour so a future regex tightening shows up in this test.
['user@example.toolongtld', true],
['', false],
[null, false],
[undefined, false],
])('isEmail(%p) → %p', (input, expected) => {
expect(isEmail(input)).toBe(expected);
});
});
describe('isPhone', () => {
it.each([
['13912345678', true],
['18512345678', true],
['14712345678', true],
['16612345678', true], // 16x prefix (China Unicom IoT)
['17812345678', true], // 17x prefix (virtual operator)
['19912345678', true], // 19x prefix (China Telecom)
['10000000000', false], // invalid prefix (10x)
['12000000000', false], // invalid prefix (12x)
['1391234567', false], // too short
['139123456789', false], // too long
['abcdefghijk', false],
['', false],
[null, false],
[undefined, false],
])('isPhone(%p) → %p', (input, expected) => {
expect(isPhone(input)).toBe(expected);
});
});
describe('isNum', () => {
// type=1: decimal-aware (digits and optional dot)
// type=2: integer-only (pure digits)
// default: always true (backward-compatible fallthrough)
it.each([
// type=1 (decimal)
['123', 1, true],
['1.5', 1, true],
['.5', 1, true],
['0', 1, true],
['abc', 1, false],
['12a', 1, false],
// type=2 (integer)
['5', 2, true],
['123', 2, true],
['1.5', 2, false],
['a5', 2, false],
// unknown type — fallthrough to true
['123', 0, true],
['abc', 99, true],
])('isNum(%p, %i) → %p', (input, type, expected) => {
expect(isNum(input, type)).toBe(expected);
});
});
describe('isNull', () => {
it.each([
[undefined, true],
[null, true],
['', true],
['null', true],
['undefined', true],
['ok', false],
[0, false], // numbers are never null
[-1, false],
[Number.NaN, false],
[false, false], // booleans are never null
[true, false],
[[], true],
[[1], false],
[{}, true],
[{a: 1}, false],
])('isNull(%p) → %p', (input, expected) => {
expect(isNull(input)).toBe(expected);
});
it('treats nested empty arrays/objects as non-null', () => {
expect(isNull([[]])).toBe(false);
expect(isNull({nested: {}})).toBe(false);
});
});
});