extwee 2.2.1 → 2.2.2

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.
Files changed (49) hide show
  1. package/.github/codeql-analysis.yml +51 -0
  2. package/README.md +9 -3
  3. package/docs/objects/story.md +1 -2
  4. package/index.js +2 -0
  5. package/package.json +17 -17
  6. package/src/IFID/generate.js +20 -0
  7. package/src/JSON/parse.js +43 -0
  8. package/src/Passage.js +52 -3
  9. package/src/Story.js +266 -107
  10. package/src/StoryFormat/parse.js +190 -80
  11. package/src/StoryFormat.js +78 -88
  12. package/src/TWS/parse.js +2 -2
  13. package/src/Twee/parse.js +2 -3
  14. package/src/Twine1HTML/compile.js +2 -0
  15. package/src/Twine1HTML/parse.js +2 -3
  16. package/src/Twine2ArchiveHTML/compile.js +8 -0
  17. package/src/Twine2ArchiveHTML/parse.js +33 -3
  18. package/src/Twine2HTML/compile.js +31 -6
  19. package/src/Twine2HTML/parse.js +49 -54
  20. package/test/IFID/IFID.Generate.test.js +10 -0
  21. package/test/JSON/JSON.Parse.test.js +4 -4
  22. package/test/Story.test.js +256 -46
  23. package/test/StoryFormat/StoryFormat.Parse.test.js +442 -55
  24. package/test/StoryFormat.test.js +9 -2
  25. package/test/TWS/Parse.test.js +1 -1
  26. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Parse.test.js +20 -4
  27. package/test/Twine2HTML/Twine2HTML.Compile.test.js +35 -120
  28. package/test/Twine2HTML/Twine2HTML.Parse.test.js +57 -38
  29. package/test/Twine2HTML/Twine2HTMLCompiler/format.js +9 -0
  30. package/test/Twine2HTML/Twine2HTMLParser/missingZoom.html +1 -1
  31. package/web-index.js +2 -0
  32. package/test/StoryFormat/StoryFormatParser/example.js +0 -3
  33. package/test/StoryFormat/StoryFormatParser/example2.js +0 -3
  34. package/test/StoryFormat/StoryFormatParser/format.js +0 -1
  35. package/test/StoryFormat/StoryFormatParser/format_doublename.js +0 -1
  36. package/test/StoryFormat/StoryFormatParser/harlowe.js +0 -3
  37. package/test/StoryFormat/StoryFormatParser/missingAuthor.js +0 -1
  38. package/test/StoryFormat/StoryFormatParser/missingDescription.js +0 -1
  39. package/test/StoryFormat/StoryFormatParser/missingImage.js +0 -1
  40. package/test/StoryFormat/StoryFormatParser/missingLicense.js +0 -1
  41. package/test/StoryFormat/StoryFormatParser/missingName.js +0 -1
  42. package/test/StoryFormat/StoryFormatParser/missingProofing.js +0 -1
  43. package/test/StoryFormat/StoryFormatParser/missingSource.js +0 -1
  44. package/test/StoryFormat/StoryFormatParser/missingURL.js +0 -1
  45. package/test/StoryFormat/StoryFormatParser/missingVersion.js +0 -1
  46. package/test/StoryFormat/StoryFormatParser/versionWrong.js +0 -1
  47. package/test/Twine2HTML/Twine2HTMLParser/missingName.html +0 -33
  48. package/test/Twine2HTML/Twine2HTMLParser/missingPID.html +0 -15
  49. package/test/Twine2HTML/Twine2HTMLParser/missingPassageName.html +0 -15
@@ -1,91 +1,478 @@
1
1
  import { parse as parseStoryFormat } from '../../src/StoryFormat/parse.js';
2
- import { readFileSync } from 'node:fs';
3
2
 
4
3
  describe('StoryFormat', () => {
5
4
  describe('parse()', () => {
5
+ describe('Removing setup', () => {
6
+ it('Should remove setup', () => {
7
+ const fr = 'window.storyFormat({"author":"A","description":"B","image":"C","name":"harlowe","proofing":false,"license":"MIT","source":"<html></html>","url":"example.com","version":"1.0.0","setup": function(){}});';
8
+ const sfp = parseStoryFormat(fr);
9
+ expect(sfp.name).toBe('harlowe');
10
+ expect(sfp.version).toBe('1.0.0');
11
+ expect(sfp.author).toBe('A');
12
+ expect(sfp.description).toBe('B');
13
+ expect(sfp.image).toBe('C');
14
+ expect(sfp.url).toBe('example.com');
15
+ expect(sfp.license).toBe('MIT');
16
+ expect(sfp.proofing).toBe(false);
17
+ });
18
+ });
19
+
20
+ describe('name', function () {
21
+ const fr = `{
22
+ "name": "My Story Format",
23
+ "version": "1.0.0",
24
+ "author": "Twine",
25
+ "description": "A story format.",
26
+ "image": "icon.svg",
27
+ "url": "https://example.com",
28
+ "license": "MIT",
29
+ "proofing": false,
30
+ "source": "<html></html>"
31
+ }`;
32
+
33
+ it('Should parse a name', () => {
34
+ const sfp = parseStoryFormat(fr);
35
+ expect(sfp.name).toBe('My Story Format');
36
+ });
37
+
38
+ it('Should detect missing name and set default', () => {
39
+ const copy = JSON.parse(fr);
40
+ delete copy.name;
41
+ const sfp = parseStoryFormat(JSON.stringify(copy));
42
+ expect(sfp.name).toBe('Untitled Story Format');
43
+ });
44
+ });
45
+
46
+ describe('author', function () {
47
+ const fr = `{
48
+ "name": "My Story Format",
49
+ "version": "1.0.0",
50
+ "author": "Twine",
51
+ "description": "A story format.",
52
+ "image": "icon.svg",
53
+ "url": "https://example.com",
54
+ "license": "MIT",
55
+ "proofing": false,
56
+ "source": "<html></html>"
57
+ }`;
58
+
59
+ it('Should parse an author', () => {
60
+ const sfp = parseStoryFormat(fr);
61
+ expect(sfp.author).toBe('Twine');
62
+ });
63
+
64
+ it('Should detect missing author and set default', () => {
65
+ const copy = JSON.parse(fr);
66
+ delete copy.author;
67
+ const sfp = parseStoryFormat(JSON.stringify(copy));
68
+ expect(sfp.author).toBe('');
69
+ });
70
+ });
71
+
72
+ describe('description', function () {
73
+ const fr = `{
74
+ "name": "My Story Format",
75
+ "version": "1.0.0",
76
+ "author": "Twine",
77
+ "description": "A story format.",
78
+ "image": "icon.svg",
79
+ "url": "https://example.com",
80
+ "license": "MIT",
81
+ "proofing": false,
82
+ "source": "<html></html>"
83
+ }`;
84
+
85
+ it('Should parse a description', () => {
86
+ const sfp = parseStoryFormat(fr);
87
+ expect(sfp.description).toBe('A story format.');
88
+ });
89
+
90
+ it('Should detect missing description and set default', () => {
91
+ const copy = JSON.parse(fr);
92
+ delete copy.description;
93
+ const sfp = parseStoryFormat(JSON.stringify(copy));
94
+ expect(sfp.description).toBe('');
95
+ });
96
+ });
97
+
98
+ describe('image', function () {
99
+ const fr = `{
100
+ "name": "My Story Format",
101
+ "version": "1.0.0",
102
+ "author": "Twine",
103
+ "description": "A story format.",
104
+ "image": "icon.svg",
105
+ "url": "https://example.com",
106
+ "license": "MIT",
107
+ "proofing": false,
108
+ "source": "<html></html>"
109
+ }`;
110
+
111
+ it('Should parse an image', () => {
112
+ const sfp = parseStoryFormat(fr);
113
+ expect(sfp.image).toBe('icon.svg');
114
+ });
115
+
116
+ it('Should detect missing image and set default', () => {
117
+ const copy = JSON.parse(fr);
118
+ delete copy.image;
119
+ const sfp = parseStoryFormat(JSON.stringify(copy));
120
+ expect(sfp.image).toBe('');
121
+ });
122
+ });
123
+
124
+ describe('url', function () {
125
+ const fr = `{
126
+ "name": "My Story Format",
127
+ "version": "1.0.0",
128
+ "author": "Twine",
129
+ "description": "A story format.",
130
+ "image": "icon.svg",
131
+ "url": "https://example.com",
132
+ "license": "MIT",
133
+ "proofing": false,
134
+ "source": "<html></html>"
135
+ }`;
136
+
137
+ it('Should parse a url', () => {
138
+ const sfp = parseStoryFormat(fr);
139
+ expect(sfp.url).toBe('https://example.com');
140
+ });
141
+
142
+ it('Should detect missing url and set default', () => {
143
+ const copy = JSON.parse(fr);
144
+ delete copy.url;
145
+ const sfp = parseStoryFormat(JSON.stringify(copy));
146
+ expect(sfp.url).toBe('');
147
+ });
148
+ });
149
+
150
+ describe('version', function () {
151
+ const fr = `{
152
+ "name": "My Story Format",
153
+ "version": "1.0.0",
154
+ "author": "Twine",
155
+ "description": "A story format.",
156
+ "image": "icon.svg",
157
+ "url": "https://example.com",
158
+ "license": "MIT",
159
+ "proofing": false,
160
+ "source": "<html></html>"
161
+ }`;
162
+
163
+ it('Should parse a version', () => {
164
+ const sfp = parseStoryFormat(fr);
165
+ expect(sfp.version).toBe('1.0.0');
166
+ });
167
+ });
168
+
169
+ describe('license', function () {
170
+ const fr = `{
171
+ "name": "My Story Format",
172
+ "version": "1.0.0",
173
+ "author": "Twine",
174
+ "description": "A story format.",
175
+ "image": "icon.svg",
176
+ "url": "https://example.com",
177
+ "license": "MIT",
178
+ "proofing": false,
179
+ "source": "<html></html>"
180
+ }`;
181
+
182
+ it('Should parse a license', () => {
183
+ const sfp = parseStoryFormat(fr);
184
+ expect(sfp.license).toBe('MIT');
185
+ });
186
+
187
+ it('Should detect missing license and set default', () => {
188
+ const copy = JSON.parse(fr);
189
+ delete copy.license;
190
+ const sfp = parseStoryFormat(JSON.stringify(copy));
191
+ expect(sfp.license).toBe('');
192
+ });
193
+ });
194
+
195
+ describe('proofing', function () {
196
+ const fr = `{
197
+ "name": "My Story Format",
198
+ "version": "1.0.0",
199
+ "author": "Twine",
200
+ "description": "A story format.",
201
+ "image": "icon.svg",
202
+ "url": "https://example.com",
203
+ "license": "MIT",
204
+ "proofing": true,
205
+ "source": "<html></html>"
206
+ }`;
207
+
208
+ it('Should parse proofing', () => {
209
+ const sfp = parseStoryFormat(fr);
210
+ expect(sfp.proofing).toBe(true);
211
+ });
212
+
213
+ it('Should detect missing proofing and set default', () => {
214
+ const copy = JSON.parse(fr);
215
+ delete copy.proofing;
216
+ const sfp = parseStoryFormat(JSON.stringify(copy));
217
+ expect(sfp.proofing).toBe(false);
218
+ });
219
+ });
220
+
221
+ describe('source', function () {
222
+ const fr = `{
223
+ "name": "My Story Format",
224
+ "version": "1.0.0",
225
+ "author": "Twine",
226
+ "description": "A story format.",
227
+ "image": "icon.svg",
228
+ "url": "https://example.com",
229
+ "license": "MIT",
230
+ "proofing": true,
231
+ "source": "<html></html>"
232
+ }`;
233
+
234
+ it('Should parse a source', () => {
235
+ const sfp = parseStoryFormat(fr);
236
+ expect(sfp.source).toBe('<html></html>');
237
+ });
238
+ });
239
+ });
240
+
241
+ describe('Errors', function () {
6
242
  it('Should throw error if JSON missing', () => {
7
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/example.js', 'utf-8');
243
+ const fr = '[]';
8
244
  expect(() => { parseStoryFormat(fr); }).toThrow();
9
245
  });
10
246
 
11
- it('Should throw error if JSON malformed', () => {
12
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/example2.js', 'utf-8');
247
+ it('Should throw error if JSON is malformed', () => {
248
+ const fr = '{"state"}';
13
249
  expect(() => { parseStoryFormat(fr); }).toThrow();
14
250
  });
251
+ });
252
+
253
+ describe('Warnings', () => {
254
+ beforeEach(() => {
255
+ // Mock console.warn.
256
+ jest.spyOn(console, 'warn').mockImplementation();
257
+ });
258
+
259
+ afterEach(() => {
260
+ // Restore all mocks.
261
+ jest.restoreAllMocks();
262
+ });
15
263
 
16
- it('Should correctly parse a StoryFormat name', () => {
17
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
18
- const sfp = parseStoryFormat(fr);
19
- expect(sfp.name).toBe('Snowman');
264
+ it('Should produce warning if name is not a string', () => {
265
+ const fr = `{
266
+ "name": null,
267
+ "version": "1.0.0",
268
+ "author": "Twine",
269
+ "description": "A story format.",
270
+ "image": "icon.svg",
271
+ "url": "https://example.com",
272
+ "license": "MIT",
273
+ "proofing": true,
274
+ "source": "<html></html>"
275
+ }`;
276
+ // Parse the story format.
277
+ parseStoryFormat(fr);
278
+ // Expect warning.
279
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s name is not a string. It will be ignored.');
20
280
  });
21
281
 
22
- it('Should correctly parse Harlowe story format', () => {
23
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/harlowe.js', 'utf-8');
24
- const sfp = parseStoryFormat(fr);
25
- expect(sfp.name).toBe('Harlowe');
282
+ it('Should produce warning if author is not a string', () => {
283
+ const fr = `{
284
+ "name": "My Story Format",
285
+ "version": "1.0.0",
286
+ "author": null,
287
+ "description": "A story format.",
288
+ "image": "icon.svg",
289
+ "url": "https://example.com",
290
+ "license": "MIT",
291
+ "proofing": true,
292
+ "source": "<html></html>"
293
+ }`;
294
+ // Parse the story format.
295
+ parseStoryFormat(fr);
296
+ // Expect warning.
297
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s author is not a string. It will be ignored.');
26
298
  });
27
299
 
28
- it('Should detect missing name and set default', () => {
29
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingName.js', 'utf-8');
30
- const sfp = parseStoryFormat(fr);
31
- expect(sfp.name).toBe('Untitled Story Format');
300
+ it('Should produce warning if description is not a string', () => {
301
+ const fr = `{
302
+ "name": "My Story Format",
303
+ "version": "1.0.0",
304
+ "author": "Twine",
305
+ "description": null,
306
+ "image": "icon.svg",
307
+ "url": "https://example.com",
308
+ "license": "MIT",
309
+ "proofing": true,
310
+ "source": "<html></html>"
311
+ }`;
312
+ // Parse the story format.
313
+ parseStoryFormat(fr);
314
+ // Expect warning.
315
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s description is not a string. It will be ignored.');
32
316
  });
33
317
 
34
- it('Should detect missing author and set default', () => {
35
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingAuthor.js', 'utf-8');
36
- const sfp = parseStoryFormat(fr);
37
- expect(sfp.author).toBe('');
318
+ it('Should produce warning if image is not a string', () => {
319
+ const fr = `{
320
+ "name": "My Story Format",
321
+ "version": "1.0.0",
322
+ "author": "Twine",
323
+ "description": "A story format.",
324
+ "image": null,
325
+ "url": "https://example.com",
326
+ "license": "MIT",
327
+ "proofing": true,
328
+ "source": "<html></html>"
329
+ }`;
330
+ // Parse the story format.
331
+ parseStoryFormat(fr);
332
+ // Expect warning.
333
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s image is not a string. It will be ignored.');
38
334
  });
39
335
 
40
- it('Should detect missing description and set default', () => {
41
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingDescription.js', 'utf-8');
42
- const sfp = parseStoryFormat(fr);
43
- expect(sfp.description).toBe('');
336
+ it('Should produce warning if url is not a string', () => {
337
+ const fr = `{
338
+ "name": "My Story Format",
339
+ "version": "1.0.0",
340
+ "author": "Twine",
341
+ "description": "A story format.",
342
+ "image": "icon.svg",
343
+ "url": null,
344
+ "license": "MIT",
345
+ "proofing": true,
346
+ "source": "<html></html>"
347
+ }`;
348
+ // Parse the story format.
349
+ parseStoryFormat(fr);
350
+ // Expect warning.
351
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s url is not a string. It will be ignored.');
44
352
  });
45
353
 
46
- it('Should detect missing image and set default', () => {
47
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingImage.js', 'utf-8');
48
- const sfp = parseStoryFormat(fr);
49
- expect(sfp.image).toBe('');
354
+ it('Should produce warning if license is not a string', () => {
355
+ const fr = `{
356
+ "name": "My Story Format",
357
+ "version": "1.0.0",
358
+ "author": "Twine",
359
+ "description": "A story format.",
360
+ "image": "icon.svg",
361
+ "url": "https://example.com",
362
+ "license": null,
363
+ "proofing": true,
364
+ "source": "<html></html>"
365
+ }`;
366
+ // Parse the story format.
367
+ parseStoryFormat(fr);
368
+ // Expect warning.
369
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s license is not a string. It will be ignored.');
50
370
  });
51
371
 
52
- it('Should detect missing url and set default', () => {
53
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingURL.js', 'utf-8');
54
- const sfp = parseStoryFormat(fr);
55
- expect(sfp.url).toBe('');
372
+ it('Should produce warning if proofing is not a boolean', () => {
373
+ const fr = `{
374
+ "name": "My Story Format",
375
+ "version": "1.0.0",
376
+ "author": "Twine",
377
+ "description": "A story format.",
378
+ "image": "icon.svg",
379
+ "url": "https://example.com",
380
+ "license": "MIT",
381
+ "proofing": null,
382
+ "source": "<html></html>"
383
+ }`;
384
+ // Parse the story format.
385
+ parseStoryFormat(fr);
386
+ // Expect warning.
387
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s proofing is not a boolean. It will be ignored.');
56
388
  });
57
389
 
58
- it('Should detect missing license and set default', () => {
59
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingLicense.js', 'utf-8');
60
- const sfp = parseStoryFormat(fr);
61
- expect(sfp.license).toBe('');
390
+ it('Should produce warning if source is not a string', () => {
391
+ const fr = `{
392
+ "name": "My Story Format",
393
+ "version": "1.0.0",
394
+ "author": "Twine",
395
+ "description": "A story format.",
396
+ "image": "icon.svg",
397
+ "url": "https://example.com",
398
+ "license": "MIT",
399
+ "proofing": true,
400
+ "source": null
401
+ }`;
402
+ // Parse the story format.
403
+ parseStoryFormat(fr);
404
+ // Expect warning.
405
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s source is not a string! It will be ignored.');
62
406
  });
63
407
 
64
- it('Should detect proofing license and set default', () => {
65
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingProofing.js', 'utf-8');
66
- const sfp = parseStoryFormat(fr);
67
- expect(sfp.proofing).toBe(false);
408
+ it('Should produce warning if source is missing', () => {
409
+ const fr = `{
410
+ "name": "My Story Format",
411
+ "version": "1.0.0",
412
+ "author": "Twine",
413
+ "description": "A story format.",
414
+ "image": "icon.svg",
415
+ "url": "https://example.com",
416
+ "license": "MIT",
417
+ "proofing": true
418
+ }`;
419
+ // Parse the story format.
420
+ parseStoryFormat(fr);
421
+ // Expect warning.
422
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format does not have source property!');
68
423
  });
69
424
 
70
- it('Should throw error if version does not exist', () => {
71
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingVersion.js', 'utf-8');
72
- expect(() => {
73
- parseStoryFormat(fr);
74
- }).toThrow();
425
+ it('Should produce warning if version is not a string', () => {
426
+ const fr = `{
427
+ "name": "My Story Format",
428
+ "version": null,
429
+ "author": "Twine",
430
+ "description": "A story format.",
431
+ "image": "icon.svg",
432
+ "url": "https://example.com",
433
+ "license": "MIT",
434
+ "proofing": true,
435
+ "source": "<html></html>"
436
+ }`;
437
+ // Parse the story format.
438
+ parseStoryFormat(fr);
439
+ // Expect warning.
440
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s version is not a string! It will be ignored.');
75
441
  });
76
442
 
77
- it('Should throw error if version is not semantic style', () => {
78
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/versionWrong.js', 'utf-8');
79
- expect(() => {
80
- parseStoryFormat(fr);
81
- }).toThrow();
443
+ it('Should produce warning if version is not semantic', () => {
444
+ const fr = `{
445
+ "name": "My Story Format",
446
+ "version": "fake version",
447
+ "author": "Twine",
448
+ "description": "A story format.",
449
+ "image": "icon.svg",
450
+ "url": "https://example.com",
451
+ "license": "MIT",
452
+ "proofing": true,
453
+ "source": "<html></html>"
454
+ }`;
455
+ // Parse the story format.
456
+ parseStoryFormat(fr);
457
+ // Expect warning.
458
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format\'s version is not semantic! It will be ignored.');
82
459
  });
83
460
 
84
- it('Should throw error if source is not found', () => {
85
- const fr = readFileSync('test/StoryFormat/StoryFormatParser/missingSource.js', 'utf-8');
86
- expect(() => {
87
- parseStoryFormat(fr);
88
- }).toThrow();
461
+ it('Should produce warning if version is missing', () => {
462
+ const fr = `{
463
+ "name": "My Story Format",
464
+ "author": "Twine",
465
+ "description": "A story format.",
466
+ "image": "icon.svg",
467
+ "url": "https://example.com",
468
+ "license": "MIT",
469
+ "proofing": true,
470
+ "source": "<html></html>"
471
+ }`;
472
+ // Parse the story format.
473
+ parseStoryFormat(fr);
474
+ // Expect warning.
475
+ expect(console.warn).toHaveBeenCalledWith('Warning: Processed story format does not have version property!');
89
476
  });
90
477
  });
91
478
  });
@@ -1,8 +1,8 @@
1
1
  import StoryFormat from '../src/StoryFormat.js';
2
2
 
3
3
  describe('StoryFormat', () => {
4
- describe('constructor()', () => {
5
- it('Should create default values', () => {
4
+ describe('Default values', () => {
5
+ it('Should have default values', () => {
6
6
  const sf = new StoryFormat();
7
7
  expect(sf.name).toBe('Untitled Story Format');
8
8
  expect(sf.version).toBe('');
@@ -149,4 +149,11 @@ describe('StoryFormat', () => {
149
149
  }).toThrow();
150
150
  });
151
151
  });
152
+
153
+ describe('toString', () => {
154
+ it('Should return string representation', () => {
155
+ const sf = new StoryFormat();
156
+ expect(sf.toString()).toBe(JSON.stringify(sf, null, "\t"));
157
+ });
158
+ });
152
159
  });
@@ -71,7 +71,7 @@ describe('TWSParser', () => {
71
71
  const contents = fs.readFileSync('test/TWS/TWSParser/noscale.tws', 'binary');
72
72
  const b = Buffer.from(contents, 'binary');
73
73
  const r = parseTWS(b);
74
- expect(r.zoom).toBe(0);
74
+ expect(r.zoom).toBe(1);
75
75
  });
76
76
  });
77
77
  });
@@ -3,10 +3,6 @@ import { readFileSync } from 'node:fs';
3
3
 
4
4
  describe('Twine2ArchiveHTML', function () {
5
5
  describe('parse()', function () {
6
- it('Should throw error when given no Twine 2 HTML elements', function () {
7
- expect(() => { parseTwine2ArchiveHTML(''); }).toThrow();
8
- });
9
-
10
6
  it('Should throw error when content is not string', function () {
11
7
  expect(() => { parseTwine2ArchiveHTML(2); }).toThrow();
12
8
  });
@@ -22,4 +18,24 @@ describe('Twine2ArchiveHTML', function () {
22
18
  expect(stories.length).toBe(2);
23
19
  });
24
20
  });
21
+
22
+ describe('Warnings', function () {
23
+ beforeEach(() => {
24
+ // Mock console.warn.
25
+ jest.spyOn(console, 'warn').mockImplementation();
26
+ });
27
+
28
+ afterEach(() => {
29
+ // Restore all mocks.
30
+ jest.restoreAllMocks();
31
+ });
32
+
33
+ it('Should produce warning when no Twine 2 HTML content is found', function () {
34
+ // Parse Twine 2 Story.
35
+ parseTwine2ArchiveHTML('');
36
+
37
+ // Expect warning.
38
+ expect(console.warn).toHaveBeenCalledWith('Warning: No Twine 2 HTML content found!');
39
+ });
40
+ });
25
41
  });