feat(ascii-art): 19 named ASCII art templates with snapshot tests

Per Task 3 of the 2026-09-14 ASCII art upgrade plan.

- New module: src/main/AsciiArt.templates.js exporting ASCII_TEMPLATES
  (19 entries) and getTemplate(name) accessor (returns '' for unknown).
- New test: tests/main/ascii-art.templates.test.js with 19 per-template
  snapshots + unknown-name + keys-match assertions (21 tests total).
- 17 templates verbatim from src/ascii-generator.html:596-626
  (arrow-right, arrow-down, decision, process, flowchart, sequence,
  network, hierarchy, header, note, warning, info, divider, separator,
  banner, checklist + the brief's own TEMPLATE_NAMES order).
- 2 templates verbatim from src/renderer.js:6542-6697
  (progress-bar, table-simple).
- 1 newly authored: arrow-up (completes the arrow triplet; does not
  exist in either source).

Amit Haridas
This commit is contained in:
2026-09-14 20:35:39 +05:30
parent f71aa2b097
commit bb99a5c5ee
3 changed files with 287 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
/**
* ASCII art templates — named pre-drawn diagrams and frames.
*
* Sourced from src/ascii-generator.html:596-626 and src/renderer.js:6542-6697
* (the `getASCIITemplate()` function). 19 entries; unknown names resolve to ''.
* `arrow-up` is the only template authored for this module — it completes the
* arrow triplet (right, down, up) and does not exist verbatim in either source.
*
* @module AsciiArt.templates
*/
'use strict';
const ASCII_TEMPLATES = {
// ----- arrows -----
'arrow-right':
' ┌─────────────────────┐\n──▶│ Process or Action │──▶\n └─────────────────────┘',
'arrow-down':
' │\n ▼\n┌───────────────┐\n│ Process │\n└───────────────┘\n │\n ▼',
// Newly authored to complete the arrow triplet. Mirrors arrow-down with
// upward flow direction.
'arrow-up':
' ▲\n │\n┌───────────────┐\n│ Process │\n└───────────────┘\n │\n ▲',
// ----- shapes -----
decision:
' ╱╲\n ╱ ╲\n ╱ ? ╲\n ╱ ╲\n ╱────────╲\n ╱ ╲\n YES NO\n │ │\n ▼ ▼',
process: '┌─────┐ ┌─────┐ ┌─────┐\n│ 1 │──▶│ 2 │──▶│ 3 │\n└─────┘ └─────┘ └─────┘',
flowchart:
'┌─────────────┐\n│ START │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ Process A │\n└──────┬──────┘\n │\n ▼\n ╱────────╲\n ╱ Decision ╲\n ╲ ? ╱\n ╲────────╱\n │ │\n YES NO\n │ │\n ▼ ▼\n┌──────┐ ┌──────┐\n│ B │ │ C │\n└──────┘ └──────┘',
sequence:
' User System Database\n │ │ │\n │ Request │ │\n ├──────────►│ │\n │ │ Query │\n │ ├──────────►│\n │ │ │\n │ │ Result │\n │ │◄──────────┤\n │ Response │ │\n │◄──────────┤ │\n │ │ │',
network:
' ┌─────────┐\n │ Server │\n └────┬────┘\n │\n ┌─────────┼─────────┐\n │ │ │\n┌────┴────┐ ┌──┴──┐ ┌────┴────┐\n│ Client1 │ │ DB │ │ Client2 │\n└─────────┘ └─────┘ └─────────┘',
hierarchy:
' ┌─────────┐\n │ CEO │\n └────┬────┘\n ┌─────────┼─────────┐\n │ │ │\n ┌───┴───┐ ┌───┴───┐ ┌───┴───┐\n │ VP1 │ │ VP2 │ │ VP3 │\n └───┬───┘ └───┬───┘ └───┬───┘\n │ │ │\n ┌───┴───┐ ┌───┴───┐ ┌───┴───┐\n │ Team1 │ │ Team2 │ │ Team3 │\n └───────┘ └───────┘ └───────┘',
// ----- frames -----
header:
'╔════════════════════════════════════╗\n║ SECTION TITLE ║\n╚════════════════════════════════════╝',
note: '┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n┃ NOTE: ┃\n┃ This is an important note ┃\n┃ that requires attention! ┃\n┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛',
warning:
'╔════════════════════════════════════╗\n║ ⚠️ WARNING ║\n║ ║\n║ Critical information here! ║\n╚════════════════════════════════════╝',
info: '╭────────────────────────────────────╮\n│ ℹ️ INFO │\n│ │\n│ Helpful information here. │\n╰────────────────────────────────────╯',
divider: '════════════════════════════════════════',
separator:
'╭──────────────────────────────────────╮\n│ │\n╰──────────────────────────────────────╯',
banner:
'★══════════════════════════════════════★\n║ YOUR TITLE HERE ║\n★══════════════════════════════════════★',
checklist:
'☐ Task 1 - Not completed\n☑ Task 2 - Completed \n☐ Task 3 - Not completed\n☐ Task 4 - Not completed',
// ----- bars / tables (only in src/renderer.js) -----
'progress-bar': '\nProgress: [████████████░░░░░░░░] 60%\n 0% 100%',
'table-simple':
'\n┌──────────┬──────────┬──────────┐\n│ Header 1 │ Header 2 │ Header 3 │\n├──────────┼──────────┼──────────┤\n│ Data 1 │ Data 2 │ Data 3 │\n├──────────┼──────────┼──────────┤\n│ Data 4 │ Data 5 │ Data 6 │\n└──────────┴──────────┴──────────┘',
};
function getTemplate(name) {
if (typeof name !== 'string') return '';
return ASCII_TEMPLATES[name] || '';
}
module.exports = { ASCII_TEMPLATES, getTemplate };
@@ -0,0 +1,179 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`AsciiArt.templates arrow-down 1`] = `
" │
▼
┌───────────────┐
│ Process │
└───────────────┘
│
▼"
`;
exports[`AsciiArt.templates arrow-right 1`] = `
" ┌─────────────────────┐
──▶│ Process or Action │──▶
└─────────────────────┘"
`;
exports[`AsciiArt.templates arrow-up 1`] = `
" ▲
│
┌───────────────┐
│ Process │
└───────────────┘
│
▲"
`;
exports[`AsciiArt.templates banner 1`] = `
"★══════════════════════════════════════★
║ YOUR TITLE HERE ║
★══════════════════════════════════════★"
`;
exports[`AsciiArt.templates checklist 1`] = `
"☐ Task 1 - Not completed
☑ Task 2 - Completed
☐ Task 3 - Not completed
☐ Task 4 - Not completed"
`;
exports[`AsciiArt.templates decision 1`] = `
" ╱╲
╱ ╲
╱ ? ╲
╱ ╲
╱────────╲
╱ ╲
YES NO
│ │
▼ ▼"
`;
exports[`AsciiArt.templates divider 1`] = `"════════════════════════════════════════"`;
exports[`AsciiArt.templates flowchart 1`] = `
"┌─────────────┐
│ START │
└──────┬──────┘
│
▼
┌─────────────┐
│ Process A │
└──────┬──────┘
│
▼
╱────────╲
╱ Decision ╲
╲ ? ╱
╲────────╱
│ │
YES NO
│ │
▼ ▼
┌──────┐ ┌──────┐
│ B │ │ C │
└──────┘ └──────┘"
`;
exports[`AsciiArt.templates header 1`] = `
"╔════════════════════════════════════╗
║ SECTION TITLE ║
╚════════════════════════════════════╝"
`;
exports[`AsciiArt.templates hierarchy 1`] = `
" ┌─────────┐
│ CEO │
└────┬────┘
┌─────────┼─────────┐
│ │ │
┌───┴───┐ ┌───┴───┐ ┌───┴───┐
│ VP1 │ │ VP2 │ │ VP3 │
└───┬───┘ └───┬───┘ └───┬───┘
│ │ │
┌───┴───┐ ┌───┴───┐ ┌───┴───┐
│ Team1 │ │ Team2 │ │ Team3 │
└───────┘ └───────┘ └───────┘"
`;
exports[`AsciiArt.templates info 1`] = `
"╭────────────────────────────────────╮
│ ℹ️ INFO │
│ │
│ Helpful information here. │
╰────────────────────────────────────╯"
`;
exports[`AsciiArt.templates network 1`] = `
" ┌─────────┐
│ Server │
└────┬────┘
│
┌─────────┼─────────┐
│ │ │
┌────┴────┐ ┌──┴──┐ ┌────┴────┐
│ Client1 │ │ DB │ │ Client2 │
└─────────┘ └─────┘ └─────────┘"
`;
exports[`AsciiArt.templates note 1`] = `
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ NOTE: ┃
┃ This is an important note ┃
┃ that requires attention! ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
`;
exports[`AsciiArt.templates process 1`] = `
"┌─────┐ ┌─────┐ ┌─────┐
│ 1 │──▶│ 2 │──▶│ 3 │
└─────┘ └─────┘ └─────┘"
`;
exports[`AsciiArt.templates progress-bar 1`] = `
"
Progress: [████████████░░░░░░░░] 60%
0% 100%"
`;
exports[`AsciiArt.templates separator 1`] = `
"╭──────────────────────────────────────╮
│ │
╰──────────────────────────────────────╯"
`;
exports[`AsciiArt.templates sequence 1`] = `
" User System Database
│ │ │
│ Request │ │
├──────────►│ │
│ │ Query │
│ ├──────────►│
│ │ │
│ │ Result │
│ │◄──────────┤
│ Response │ │
│◄──────────┤ │
│ │ │"
`;
exports[`AsciiArt.templates table-simple 1`] = `
"
┌──────────┬──────────┬──────────┐
│ Header 1 │ Header 2 │ Header 3 │
├──────────┼──────────┼──────────┤
│ Data 1 │ Data 2 │ Data 3 │
├──────────┼──────────┼──────────┤
│ Data 4 │ Data 5 │ Data 6 │
└──────────┴──────────┴──────────┘"
`;
exports[`AsciiArt.templates warning 1`] = `
"╔════════════════════════════════════╗
║ ⚠️ WARNING ║
║ ║
║ Critical information here! ║
╚════════════════════════════════════╝"
`;
+45
View File
@@ -0,0 +1,45 @@
/**
* @jest-environment node
*
* Per-template snapshot tests. Templates are static strings; the snapshot
* catches accidental edits during refactors.
*/
const AsciiArtTemplates = require('../../src/main/AsciiArt.templates');
const TEMPLATE_NAMES = [
'arrow-right',
'arrow-down',
'arrow-up',
'decision',
'process',
'flowchart',
'sequence',
'network',
'hierarchy',
'header',
'note',
'warning',
'info',
'divider',
'separator',
'banner',
'checklist',
'progress-bar',
'table-simple',
];
describe('AsciiArt.templates', () => {
test.each(TEMPLATE_NAMES)('%s', (name) => {
expect(AsciiArtTemplates.getTemplate(name)).toMatchSnapshot();
});
test('returns empty string for unknown name', () => {
expect(AsciiArtTemplates.getTemplate('nope')).toBe('');
});
test('ASCII_TEMPLATES object exposes all 19 names', () => {
expect(Object.keys(AsciiArtTemplates.ASCII_TEMPLATES).sort()).toEqual(
TEMPLATE_NAMES.slice().sort()
);
});
});