From ad4d6faedce2b85710bff3ac06dc3a4dc4723436 Mon Sep 17 00:00:00 2001 From: Chris Zuber Date: Mon, 5 Jan 2026 12:19:34 -0800 Subject: [PATCH] Add tests for escapeCSS and bump version to 1.0.1 Introduces comprehensive tests for the escapeCSS function in css.test.js, covering valid identifiers, syntax characters, control characters, Unicode, and type coercion. Updates package version to 1.0.1 and documents the changes in CHANGELOG.md. --- CHANGELOG.md | 6 ++++ css.test.js | 71 +++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 8 +++--- package.json | 2 +- 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 css.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index d7e983a..f37f425 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v1.0.1] - 2026-01-05 + +### Added +- Add tests for `escapeCSS()` +- This release will add Package Provenance + ## [v1.0.0] - 2026-01-05 Initial Release diff --git a/css.test.js b/css.test.js new file mode 100644 index 0000000..9391e54 --- /dev/null +++ b/css.test.js @@ -0,0 +1,71 @@ +import assert from 'node:assert'; +import { describe, test } from 'node:test'; +import { escapeCSS } from './css.js'; + +describe('escapeCSS', () => { + test('passes through valid identifiers', () => { + assert.strictEqual(escapeCSS('foo'), 'foo'); + assert.strictEqual(escapeCSS('foo-bar'), 'foo-bar'); + assert.strictEqual(escapeCSS('foo_bar'), 'foo_bar'); + assert.strictEqual(escapeCSS('FOO'), 'FOO'); + }); + + test('escapes syntax characters', () => { + // Class, ID, Pseudo-classes + assert.strictEqual(escapeCSS('foo.bar'), 'foo\\.bar'); + assert.strictEqual(escapeCSS('foo#bar'), 'foo\\#bar'); + assert.strictEqual(escapeCSS('foo:bar'), 'foo\\:bar'); + // Brackets and attributes + assert.strictEqual(escapeCSS('[data=val]'), '\\[data\\=val\\]'); + }); + + test('handles leading digits (must be hex escaped)', () => { + // 1 -> \31 + space + assert.strictEqual(escapeCSS('123'), '\\31 23'); + // 9 -> \39 + space + assert.strictEqual(escapeCSS('987'), '\\39 87'); + // 0 -> \30 + space + assert.strictEqual(escapeCSS('0abc'), '\\30 abc'); + }); + + test('handles leading hyphen followed by digit', () => { + // Hyphen remains, digit becomes hex escaped + assert.strictEqual(escapeCSS('-123'), '-\\31 23'); + assert.strictEqual(escapeCSS('-0'), '-\\30 '); + }); + + test('handles single hyphen vs double hyphen', () => { + // Single hyphen is a reserved syntax if standalone, must escape + assert.strictEqual(escapeCSS('-'), '\\-'); + + // Double hyphen is valid (starts a custom property), passes through + assert.strictEqual(escapeCSS('--var'), '--var'); + }); + + test('handles control characters', () => { + // Null byte -> Replacement Character (U+FFFD) + assert.strictEqual(escapeCSS('\u0000'), '\uFFFD'); + + // C0 Control (0x01-0x1F) -> Hex escape + space + assert.strictEqual(escapeCSS('\x01'), '\\1 '); + assert.strictEqual(escapeCSS('\x1F'), '\\1f '); + + // Delete (0x7F) -> Hex escape + space + assert.strictEqual(escapeCSS('\x7F'), '\\7f '); + }); + + test('handles high ASCII and Unicode', () => { + // Should pass through untouched + assert.strictEqual(escapeCSS('©'), '©'); + assert.strictEqual(escapeCSS('💩'), '💩'); + assert.strictEqual(escapeCSS('über'), 'über'); + }); + + test('converts non-strings to strings (IDL behavior)', () => { + assert.strictEqual(escapeCSS(123), '\\31 23'); + // String(null) -> "null" (valid identifier) + assert.strictEqual(escapeCSS(null), 'null'); + // String(undefined) -> "undefined" (valid identifier) + assert.strictEqual(escapeCSS(undefined), 'undefined'); + }); +}); diff --git a/package-lock.json b/package-lock.json index 526549c..c221a1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "npm-template", - "version": "1.1.3", + "name": "@aegisjsproject/escape", + "version": "1.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "npm-template", - "version": "1.1.3", + "name": "@aegisjsproject/escape", + "version": "1.0.1", "funding": [ { "type": "librepay", diff --git a/package.json b/package.json index b30ab1f..1c254f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aegisjsproject/escape", - "version": "1.0.0", + "version": "1.0.1", "description": "String escaping utilities for HTML and DOM attributes.", "keywords": [ "security",