text-guitar-chart 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,444 @@
1
+ // @ts-nocheck
2
+
3
+ import { describe, test } from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { EditableSVGuitarChord, DOT_COLORS } from '../lib/editableSVGuitar.js';
6
+
7
+ // Mock SVGuitarChord class for testing
8
+ class MockSVGuitarChord {
9
+ constructor(container) {
10
+ this.container = container;
11
+ this.chordConfig = {};
12
+ this.config = {};
13
+ }
14
+
15
+ chord(config) {
16
+ this.chordConfig = config;
17
+ return this;
18
+ }
19
+
20
+ configure(config) {
21
+ this.config = config;
22
+ return this;
23
+ }
24
+
25
+ draw() {
26
+ return this;
27
+ }
28
+ }
29
+
30
+ describe('EditableSVGuitarChord (Core Functionality)', () => {
31
+ test('creates instance with basic properties', () => {
32
+ // Create minimal mock DOM elements
33
+ const mockContainer = {
34
+ appendChild: () => {},
35
+ querySelector: () => null
36
+ };
37
+
38
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
39
+
40
+ assert.ok(editableChord);
41
+ assert.equal(editableChord.container, mockContainer);
42
+ assert.equal(editableChord.SVGuitarChordClass, MockSVGuitarChord);
43
+ assert.deepEqual(editableChord.chordConfig, { fingers: [], barres: [], title: undefined, position: undefined });
44
+ assert.equal(editableChord.config.frets, 5);
45
+ assert.equal(editableChord.isDialogOpen, false);
46
+ });
47
+
48
+ test('sets and gets chord configuration', () => {
49
+ const mockContainer = { appendChild: () => {} };
50
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
51
+
52
+ const testChord = {
53
+ fingers: [[1, 0], [2, 2], [3, 2]],
54
+ barres: []
55
+ };
56
+
57
+ editableChord.chord(testChord);
58
+ const result = editableChord.getChord();
59
+
60
+ assert.deepEqual(result.fingers, testChord.fingers);
61
+ assert.deepEqual(result.barres, testChord.barres);
62
+ });
63
+
64
+ test('configures SVGuitar options', () => {
65
+ const mockContainer = { appendChild: () => {} };
66
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
67
+
68
+ const testConfig = { frets: 7, tuning: ['E', 'A', 'D', 'G', 'B', 'E'] };
69
+ editableChord.configure(testConfig);
70
+
71
+ assert.equal(editableChord.config.frets, 7);
72
+ assert.deepEqual(editableChord.config.tuning, testConfig.tuning);
73
+ });
74
+
75
+ test('adds placeholder dots correctly', () => {
76
+ const mockContainer = { appendChild: () => {} };
77
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
78
+
79
+ const originalChord = {
80
+ fingers: [[1, 2, { text: '1', color: '#000000' }]],
81
+ barres: []
82
+ };
83
+
84
+ const chordWithPlaceholders = editableChord.addPlaceholderDots(originalChord);
85
+
86
+ // Should have the original finger plus many placeholders
87
+ assert.ok(chordWithPlaceholders.fingers.length > 1, 'Should add placeholder dots');
88
+
89
+ // Should preserve the original finger
90
+ const originalFinger = chordWithPlaceholders.fingers.find(([s, f, options]) =>
91
+ s === 1 && f === 2 && options && options.color === '#000000'
92
+ );
93
+ assert.ok(originalFinger, 'Should preserve original finger');
94
+
95
+ // Should have transparent placeholders
96
+ const placeholders = chordWithPlaceholders.fingers.filter(([, , options]) =>
97
+ options && options.color === 'transparent'
98
+ );
99
+ assert.ok(placeholders.length > 0, 'Should add transparent placeholders');
100
+
101
+ // Check placeholder structure
102
+ const firstPlaceholder = placeholders[0];
103
+ assert.equal(firstPlaceholder.length, 3, 'Placeholder should have 3 elements');
104
+ assert.equal(typeof firstPlaceholder[0], 'number', 'String should be number');
105
+ assert.equal(typeof firstPlaceholder[1], 'number', 'Fret should be number');
106
+ assert.equal(firstPlaceholder[2].color, 'transparent', 'Should be transparent');
107
+ assert.equal(firstPlaceholder[2].className, 'placeholder-dot', 'Should have placeholder class');
108
+ });
109
+
110
+ test('adds new dot correctly', () => {
111
+ const mockContainer = { appendChild: () => {} };
112
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
113
+
114
+ editableChord.chord({ fingers: [], barres: [] });
115
+
116
+ const originalFingerCount = editableChord.chordConfig.fingers.length;
117
+
118
+ // Add a new dot
119
+ editableChord.addDot(1, 3);
120
+
121
+ assert.equal(editableChord.chordConfig.fingers.length, originalFingerCount + 1);
122
+
123
+ const newFinger = editableChord.chordConfig.fingers.find(([s, f]) => s === 1 && f === 3);
124
+ assert.ok(newFinger, 'Should add new finger');
125
+ assert.equal(newFinger[2].text, '');
126
+ assert.equal(newFinger[2].color, '#000000');
127
+ });
128
+
129
+ test('placeholder dots cover all string/fret combinations', () => {
130
+ const mockContainer = { appendChild: () => {} };
131
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
132
+
133
+ // Set frets to 3 for easier testing
134
+ editableChord.configure({ frets: 3 });
135
+
136
+ const emptyChord = { fingers: [], barres: [] };
137
+ const chordWithPlaceholders = editableChord.addPlaceholderDots(emptyChord);
138
+
139
+ // Should have placeholders for all 6 strings x 3 frets (1-3) + 6 fret 0 placeholders = 24 positions
140
+ assert.equal(chordWithPlaceholders.fingers.length, 24);
141
+
142
+ // Check we have all combinations for frets 1-3
143
+ for (let string = 1; string <= 6; string++) {
144
+ for (let fret = 1; fret <= 3; fret++) {
145
+ const placeholder = chordWithPlaceholders.fingers.find(([s, f]) => s === string && f === fret);
146
+ assert.ok(placeholder, `Should have placeholder for string ${string}, fret ${fret}`);
147
+ assert.equal(placeholder[2].color, 'transparent');
148
+ }
149
+ }
150
+
151
+ // Check we have fret 0 placeholders for all strings
152
+ for (let string = 1; string <= 6; string++) {
153
+ const placeholder = chordWithPlaceholders.fingers.find(([s, f]) => s === string && f === 0);
154
+ assert.ok(placeholder, `Should have placeholder for string ${string}, fret 0`);
155
+ }
156
+ });
157
+
158
+ test('excludes existing fingers from placeholders', () => {
159
+ const mockContainer = { appendChild: () => {} };
160
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
161
+
162
+ editableChord.configure({ frets: 2 });
163
+
164
+ const chordWithFingers = {
165
+ fingers: [[1, 1, { text: '1' }], [2, 2, { text: '2' }]],
166
+ barres: []
167
+ };
168
+
169
+ const chordWithPlaceholders = editableChord.addPlaceholderDots(chordWithFingers);
170
+
171
+ // Should have 2 original fingers + (6 strings * 2 frets - 2 existing) placeholders + 6 fret 0 placeholders
172
+ const expectedPlaceholders = (6 * 2) - 2 + 6;
173
+ const expectedTotal = 2 + expectedPlaceholders;
174
+ assert.equal(chordWithPlaceholders.fingers.length, expectedTotal);
175
+
176
+ // Original fingers should not be placeholders
177
+ const originalFingers = chordWithPlaceholders.fingers.filter(([, , options]) =>
178
+ options && options.color !== 'transparent'
179
+ );
180
+ assert.equal(originalFingers.length, 2);
181
+
182
+ // Should not have placeholders at the existing positions
183
+ const placeholderAt1_1 = chordWithPlaceholders.fingers.find(([s, f, options]) =>
184
+ s === 1 && f === 1 && options && options.color === 'transparent'
185
+ );
186
+ const placeholderAt2_2 = chordWithPlaceholders.fingers.find(([s, f, options]) =>
187
+ s === 2 && f === 2 && options && options.color === 'transparent'
188
+ );
189
+
190
+ assert.equal(placeholderAt1_1, undefined, 'Should not have placeholder where finger exists');
191
+ assert.equal(placeholderAt2_2, undefined, 'Should not have placeholder where finger exists');
192
+ });
193
+ });
194
+
195
+ describe('DOT_COLORS', () => {
196
+ test('exports DOT_COLORS object with red and black', () => {
197
+ assert.ok(typeof DOT_COLORS === 'object', 'DOT_COLORS should be an object');
198
+ assert.ok(DOT_COLORS.RED, 'DOT_COLORS should have RED property');
199
+ assert.ok(DOT_COLORS.BLACK, 'DOT_COLORS should have BLACK property');
200
+ });
201
+
202
+ test('DOT_COLORS contains valid hex colors', () => {
203
+ Object.values(DOT_COLORS).forEach(color => {
204
+ assert.ok(typeof color === 'string', 'Color should be a string');
205
+ assert.ok(/^#[0-9a-fA-F]{6}$/.test(color), `Color ${color} should be valid hex format`);
206
+ });
207
+ });
208
+
209
+ test('DOT_COLORS has expected red and black values', () => {
210
+ assert.equal(DOT_COLORS.RED, '#e74c3c', 'RED should be correct hex value');
211
+ assert.equal(DOT_COLORS.BLACK, '#000000', 'BLACK should be correct hex value');
212
+ });
213
+ });
214
+ describe('EditableSVGuitarChord (Title and Position)', () => {
215
+ test('sets title and position via chord() method', () => {
216
+ const mockContainer = { appendChild: () => {} };
217
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
218
+
219
+ const testChord = {
220
+ fingers: [[1, 0], [2, 2]],
221
+ barres: [],
222
+ title: 'A minor',
223
+ position: 5
224
+ };
225
+
226
+ editableChord.chord(testChord);
227
+ const result = editableChord.getChord();
228
+
229
+ assert.equal(result.title, 'A minor');
230
+ assert.equal(result.position, 5);
231
+ assert.deepEqual(result.fingers, testChord.fingers);
232
+ assert.deepEqual(result.barres, testChord.barres);
233
+ });
234
+
235
+ test('getChord() returns title and position', () => {
236
+ const mockContainer = { appendChild: () => {} };
237
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
238
+
239
+ editableChord.chord({
240
+ fingers: [[3, 2]],
241
+ barres: [],
242
+ title: 'G7',
243
+ position: 3
244
+ });
245
+
246
+ const result = editableChord.getChord();
247
+
248
+ assert.equal(result.title, 'G7');
249
+ assert.equal(result.position, 3);
250
+ });
251
+
252
+ test('handles empty title and undefined position', () => {
253
+ const mockContainer = { appendChild: () => {} };
254
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
255
+
256
+ editableChord.chord({
257
+ fingers: [[1, 1]],
258
+ barres: []
259
+ });
260
+
261
+ const result = editableChord.getChord();
262
+
263
+ assert.equal(result.title, '');
264
+ assert.equal(result.position, undefined);
265
+ });
266
+
267
+ test('omits empty title from SVGuitar config', () => {
268
+ const mockContainer = { appendChild: () => {} };
269
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
270
+
271
+ editableChord.chord({
272
+ fingers: [[1, 1]],
273
+ barres: [],
274
+ title: '',
275
+ position: undefined
276
+ });
277
+
278
+ const chordWithPlaceholders = editableChord.addPlaceholderDots(editableChord.chordConfig);
279
+
280
+ assert.ok(!('title' in chordWithPlaceholders) || chordWithPlaceholders.title === undefined);
281
+ assert.ok(!('position' in chordWithPlaceholders) || chordWithPlaceholders.position === undefined);
282
+ });
283
+
284
+ test('includes title and position in SVGuitar config when set', () => {
285
+ const mockContainer = { appendChild: () => {} };
286
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
287
+
288
+ editableChord.chord({
289
+ fingers: [[1, 1]],
290
+ barres: [],
291
+ title: 'C Major',
292
+ position: 8
293
+ });
294
+
295
+ const chordWithPlaceholders = editableChord.addPlaceholderDots(editableChord.chordConfig);
296
+
297
+ assert.equal(chordWithPlaceholders.title, 'C Major');
298
+ assert.equal(chordWithPlaceholders.position, 8);
299
+ });
300
+
301
+ test('position = 0 is valid and included', () => {
302
+ const mockContainer = { appendChild: () => {} };
303
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
304
+
305
+ editableChord.chord({
306
+ fingers: [[1, 1]],
307
+ barres: [],
308
+ title: 'Open E',
309
+ position: 0
310
+ });
311
+
312
+ const result = editableChord.getChord();
313
+ const chordWithPlaceholders = editableChord.addPlaceholderDots(editableChord.chordConfig);
314
+
315
+ assert.equal(result.position, 0);
316
+ assert.equal(chordWithPlaceholders.position, 0);
317
+ });
318
+
319
+ test('noPosition config toggles when position is set', () => {
320
+ const mockContainer = { appendChild: () => {} };
321
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
322
+
323
+ // Initially noPosition should be true
324
+ assert.equal(editableChord.config.noPosition, true);
325
+
326
+ // Set position via chord()
327
+ editableChord.chord({
328
+ fingers: [],
329
+ barres: [],
330
+ position: 5
331
+ });
332
+
333
+ // noPosition should now be false
334
+ assert.equal(editableChord.config.noPosition, false);
335
+ });
336
+
337
+ test('noPosition config remains true when position is undefined', () => {
338
+ const mockContainer = { appendChild: () => {} };
339
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
340
+
341
+ editableChord.chord({
342
+ fingers: [],
343
+ barres: [],
344
+ position: undefined
345
+ });
346
+
347
+ assert.equal(editableChord.config.noPosition, true);
348
+ });
349
+
350
+ test('saveSettings updates title and position', () => {
351
+ const mockContainer = { appendChild: () => {} };
352
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
353
+
354
+ // Mock the dialog inputs
355
+ editableChord.titleInput = { value: ' D Major ' };
356
+ editableChord.positionInput = { value: '7' };
357
+
358
+ editableChord.chord({ fingers: [], barres: [] });
359
+ editableChord.saveSettings();
360
+
361
+ const result = editableChord.getChord();
362
+
363
+ assert.equal(result.title, 'D Major');
364
+ assert.equal(result.position, 7);
365
+ assert.equal(editableChord.config.noPosition, false);
366
+ });
367
+
368
+ test('saveSettings handles empty values', () => {
369
+ const mockContainer = { appendChild: () => {} };
370
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
371
+
372
+ editableChord.titleInput = { value: '' };
373
+ editableChord.positionInput = { value: '' };
374
+
375
+ editableChord.chord({ fingers: [], barres: [], title: 'Old', position: 5 });
376
+ editableChord.saveSettings();
377
+
378
+ const result = editableChord.getChord();
379
+
380
+ assert.equal(result.title, '');
381
+ assert.equal(result.position, undefined);
382
+ assert.equal(editableChord.config.noPosition, true);
383
+ });
384
+
385
+ test('saveSettings validates position range (too low)', () => {
386
+ const mockContainer = { appendChild: () => {} };
387
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
388
+
389
+ // Mock alert
390
+ let alertCalled = false;
391
+ global.alert = () => { alertCalled = true; };
392
+
393
+ editableChord.titleInput = { value: 'Test' };
394
+ editableChord.positionInput = { value: '-1' };
395
+
396
+ editableChord.chord({ fingers: [], barres: [] });
397
+ editableChord.saveSettings();
398
+
399
+ assert.ok(alertCalled, 'Should show alert for invalid position');
400
+
401
+ // Clean up
402
+ delete global.alert;
403
+ });
404
+
405
+ test('saveSettings validates position range (too high)', () => {
406
+ const mockContainer = { appendChild: () => {} };
407
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
408
+
409
+ let alertCalled = false;
410
+ global.alert = () => { alertCalled = true; };
411
+
412
+ editableChord.titleInput = { value: 'Test' };
413
+ editableChord.positionInput = { value: '31' };
414
+
415
+ editableChord.chord({ fingers: [], barres: [] });
416
+ editableChord.saveSettings();
417
+
418
+ assert.ok(alertCalled, 'Should show alert for position > 30');
419
+
420
+ delete global.alert;
421
+ });
422
+
423
+ test('onChange callback receives updated fingers after title/position change', () => {
424
+ const mockContainer = { appendChild: () => {} };
425
+ const editableChord = new EditableSVGuitarChord(mockContainer, MockSVGuitarChord);
426
+
427
+ let callbackFired = false;
428
+ let receivedFingers = null;
429
+
430
+ editableChord.onChange((chord) => {
431
+ callbackFired = true;
432
+ receivedFingers = chord.chordConfig.fingers;
433
+ });
434
+
435
+ editableChord.titleInput = { value: 'Test' };
436
+ editableChord.positionInput = { value: '5' };
437
+
438
+ editableChord.chord({ fingers: [[1, 2]], barres: [] });
439
+ editableChord.saveSettings();
440
+
441
+ assert.ok(callbackFired, 'onChange callback should be called');
442
+ assert.deepEqual(receivedFingers, [[1, 2]], 'Should pass fingers array to callback');
443
+ });
444
+ });