Browse Source

test: add unit tests for new shared utilities

umi008 4 weeks ago
parent
commit
4da9fdb62a
3 changed files with 146 additions and 0 deletions
  1. 67 0
      src/hooks/command-hook-utils.test.ts
  2. 34 0
      src/utils/escape-html.test.ts
  3. 45 0
      src/utils/frontmatter.test.ts

+ 67 - 0
src/hooks/command-hook-utils.test.ts

@@ -0,0 +1,67 @@
+import { describe, expect, it } from 'bun:test';
+import { registerCommandHook } from './command-hook-utils';
+
+describe('registerCommandHook', () => {
+  it('registers a new command when none exists', () => {
+    const config: Record<string, unknown> = {};
+    const result = registerCommandHook(
+      config,
+      'my-command',
+      'the template',
+      'A test command',
+    );
+    expect(result).toBe(true);
+    expect(config.command).toEqual({
+      'my-command': { template: 'the template', description: 'A test command' },
+    });
+  });
+
+  it('returns false when command already exists', () => {
+    const config: Record<string, unknown> = {
+      command: { 'my-command': { template: 'old', description: 'Old' } },
+    };
+    const result = registerCommandHook(
+      config,
+      'my-command',
+      'new template',
+      'New desc',
+    );
+    expect(result).toBe(false);
+    expect(config.command).toEqual({
+      'my-command': { template: 'old', description: 'Old' },
+    });
+  });
+
+  it('adds a second command alongside an existing one', () => {
+    const config: Record<string, unknown> = {
+      command: { 'cmd-a': { template: 't', description: 'd' } },
+    };
+    registerCommandHook(config, 'cmd-b', 't2', 'd2');
+    expect(config.command).toEqual({
+      'cmd-a': { template: 't', description: 'd' },
+      'cmd-b': { template: 't2', description: 'd2' },
+    });
+  });
+
+  it('creates command object when config.command is absent', () => {
+    const config: Record<string, unknown> = {};
+    registerCommandHook(config, 'test', 'tmpl', 'desc');
+    expect(config).toHaveProperty('command');
+  });
+
+  it('accepts kebab-case command names', () => {
+    const config: Record<string, unknown> = {};
+    registerCommandHook(config, 'deep-work', 'x', 'y');
+    expect(config.command).toEqual({
+      'deep-work': { template: 'x', description: 'y' },
+    });
+  });
+
+  it('accepts snake_case command names', () => {
+    const config: Record<string, unknown> = {};
+    registerCommandHook(config, 'my_cmd', 'a', 'b');
+    expect(config.command).toEqual({
+      my_cmd: { template: 'a', description: 'b' },
+    });
+  });
+});

+ 34 - 0
src/utils/escape-html.test.ts

@@ -0,0 +1,34 @@
+import { describe, expect, it } from 'bun:test';
+import { escapeHtml } from './escape-html';
+
+describe('escapeHtml', () => {
+  it('escapes ampersands', () => {
+    expect(escapeHtml('a & b')).toBe('a &amp; b');
+  });
+
+  it('escapes less-than', () => {
+    expect(escapeHtml('a < b')).toBe('a &lt; b');
+  });
+
+  it('escapes greater-than', () => {
+    expect(escapeHtml('a > b')).toBe('a &gt; b');
+  });
+
+  it('escapes double quotes', () => {
+    expect(escapeHtml('a "b" c')).toBe('a &quot;b&quot; c');
+  });
+
+  it('escapes single quotes', () => {
+    expect(escapeHtml("a 'b' c")).toBe('a &#39;b&#39; c');
+  });
+
+  it('escapes all entities in one string', () => {
+    expect(escapeHtml('<div class="a" title=\'b\'>')).toBe(
+      '&lt;div class=&quot;a&quot; title=&#39;b&#39;&gt;',
+    );
+  });
+
+  it('returns unchanged string with no special chars', () => {
+    expect(escapeHtml('hello world')).toBe('hello world');
+  });
+});

+ 45 - 0
src/utils/frontmatter.test.ts

@@ -0,0 +1,45 @@
+import { describe, expect, it } from 'bun:test';
+import { parseFrontmatter } from './frontmatter';
+
+describe('parseFrontmatter', () => {
+  it('parses basic frontmatter block', () => {
+    const input = '---\nkey: value\n---\nbody';
+    expect(parseFrontmatter(input)).toEqual({ key: 'value' });
+  });
+
+  it('returns null for content without frontmatter', () => {
+    expect(parseFrontmatter('just some text')).toBeNull();
+  });
+
+  it('strips surrounding quotes from values', () => {
+    const input = '---\ntitle: "Hello World"\n---\nbody';
+    expect(parseFrontmatter(input)).toEqual({ title: 'Hello World' });
+  });
+
+  it('handles single-quoted values', () => {
+    const input = "---\nname: 'test'\n---\nbody";
+    expect(parseFrontmatter(input)).toEqual({ name: 'test' });
+  });
+
+  it('handles multiple key-value pairs', () => {
+    const input = '---\nurl: https://example.com\ntitle: Example\n---\nbody';
+    expect(parseFrontmatter(input)).toEqual({
+      url: 'https://example.com',
+      title: 'Example',
+    });
+  });
+
+  it('handles CRLF line endings', () => {
+    const input = '---\r\nkey: value\r\n---\r\nbody';
+    expect(parseFrontmatter(input)).toEqual({ key: 'value' });
+  });
+
+  it('skips lines without key-value pattern', () => {
+    const input = '---\nkey: value\n# comment\nother: thing\n---\nbody';
+    expect(parseFrontmatter(input)).toEqual({ key: 'value', other: 'thing' });
+  });
+
+  it('returns null for missing closing delimiter', () => {
+    expect(parseFrontmatter('---\nkey: value')).toBeNull();
+  });
+});