Files
client-web/src/editableInputPlaceholders.test.mjs
T

55 lines
2.2 KiB
JavaScript

import assert from 'node:assert/strict'
import { readdirSync, readFileSync } from 'node:fs'
import path from 'node:path'
import test from 'node:test'
import { fileURLToPath } from 'node:url'
const sourceRoot = path.dirname(fileURLToPath(import.meta.url))
function collectVueFiles(directory) {
return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
const target = path.join(directory, entry.name)
return entry.isDirectory() ? collectVueFiles(target) : entry.name.endsWith('.vue') ? [target] : []
})
}
function lineNumber(source, offset) {
return source.slice(0, offset).split('\n').length
}
function hasLiteralAttribute(tag, name) {
return new RegExp(`\\s${name}(?:\\s|=|/?>)`).test(tag)
}
function isEditableNativeTextInput(tag) {
if (hasLiteralAttribute(tag, 'disabled') || hasLiteralAttribute(tag, 'readonly')) return false
const type = tag.match(/\stype\s*=\s*["']([^"']+)["']/)?.[1]?.toLowerCase() ?? 'text'
return ['text', 'search', 'email', 'tel', 'url', 'password'].includes(type)
}
test('all editable text inputs provide a user-facing placeholder', () => {
const violations = []
for (const file of collectVueFiles(sourceRoot)) {
const source = readFileSync(file, 'utf8')
const template = source.match(/<template(?:\s[^>]*)?>([\s\S]*)<\/template>/)?.[1] ?? ''
const withoutComments = template.replace(/<!--[\s\S]*?-->/g, '')
const attributeContent = String.raw`(?:[^>"']|"[^"]*"|'[^']*')*`
const tagPattern = new RegExp(`<el-input(?:-number)?\\b${attributeContent}/?>|<(?:input|textarea)\\b${attributeContent}/?>`, 'g')
for (const match of withoutComments.matchAll(tagPattern)) {
const tag = match[0]
const isElementInput = tag.startsWith('<el-input')
const editable = isElementInput
? !hasLiteralAttribute(tag, 'disabled') && !hasLiteralAttribute(tag, 'readonly')
: isEditableNativeTextInput(tag)
if (editable && !/\s:?(?:placeholder)\s*=/.test(tag)) {
violations.push(`${path.relative(sourceRoot, file)}:${lineNumber(withoutComments, match.index ?? 0)} ${tag.replace(/\s+/g, ' ')}`)
}
}
}
assert.deepEqual(violations, [], `Editable text inputs without placeholders:\n${violations.join('\n')}`)
})