@dxtmisha/functional-basic 0.1.1 → 0.2.0

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 (126) hide show
  1. package/dist/functions/copyObjectLite.d.ts +9 -0
  2. package/dist/functions/isDomData.d.ts +6 -0
  3. package/dist/library.d.ts +2 -0
  4. package/dist/library.js +414 -413
  5. package/package.json +1 -3
  6. package/src/classes/Api.ts +0 -407
  7. package/src/classes/ApiDefault.ts +0 -83
  8. package/src/classes/ApiHeaders.ts +0 -52
  9. package/src/classes/ApiPreparation.ts +0 -114
  10. package/src/classes/ApiResponse.ts +0 -293
  11. package/src/classes/ApiStatus.ts +0 -173
  12. package/src/classes/BroadcastMessage.ts +0 -73
  13. package/src/classes/Cache.ts +0 -60
  14. package/src/classes/CacheItem.ts +0 -95
  15. package/src/classes/CacheStatic.ts +0 -30
  16. package/src/classes/Cookie.ts +0 -135
  17. package/src/classes/CookieBlock.ts +0 -31
  18. package/src/classes/DataStorage.ts +0 -194
  19. package/src/classes/Datetime.ts +0 -891
  20. package/src/classes/EventItem.ts +0 -373
  21. package/src/classes/Geo.ts +0 -320
  22. package/src/classes/GeoFlag.ts +0 -386
  23. package/src/classes/GeoIntl.ts +0 -839
  24. package/src/classes/GeoPhone.ts +0 -272
  25. package/src/classes/Global.ts +0 -32
  26. package/src/classes/Hash.ts +0 -142
  27. package/src/classes/Icons.ts +0 -165
  28. package/src/classes/Loading.ts +0 -90
  29. package/src/classes/Meta.ts +0 -284
  30. package/src/classes/MetaManager.ts +0 -200
  31. package/src/classes/MetaOg.ts +0 -147
  32. package/src/classes/MetaTwitter.ts +0 -154
  33. package/src/classes/ScrollbarWidth.ts +0 -86
  34. package/src/classes/Translate.ts +0 -293
  35. package/src/classes/__tests__/Api.test.ts +0 -728
  36. package/src/classes/__tests__/ApiDefault.test.ts +0 -222
  37. package/src/classes/__tests__/ApiHeaders.test.ts +0 -447
  38. package/src/classes/__tests__/ApiPreparation.test.ts +0 -257
  39. package/src/classes/__tests__/ApiResponse.test.ts +0 -547
  40. package/src/classes/__tests__/ApiStatus.test.ts +0 -403
  41. package/src/classes/__tests__/Meta.test.ts +0 -629
  42. package/src/classes/__tests__/MetaManager.test.ts +0 -836
  43. package/src/classes/__tests__/MetaOg.test.ts +0 -677
  44. package/src/classes/__tests__/MetaTwitter.test.ts +0 -423
  45. package/src/functions/anyToString.ts +0 -36
  46. package/src/functions/applyTemplate.ts +0 -63
  47. package/src/functions/arrFill.ts +0 -10
  48. package/src/functions/copyObject.ts +0 -10
  49. package/src/functions/createElement.ts +0 -40
  50. package/src/functions/domQuerySelector.ts +0 -15
  51. package/src/functions/domQuerySelectorAll.ts +0 -15
  52. package/src/functions/encodeAttribute.ts +0 -15
  53. package/src/functions/eventStopPropagation.ts +0 -10
  54. package/src/functions/executeFunction.ts +0 -13
  55. package/src/functions/executePromise.ts +0 -19
  56. package/src/functions/forEach.ts +0 -39
  57. package/src/functions/frame.ts +0 -38
  58. package/src/functions/getAttributes.ts +0 -27
  59. package/src/functions/getClipboardData.ts +0 -13
  60. package/src/functions/getColumn.ts +0 -18
  61. package/src/functions/getElement.ts +0 -35
  62. package/src/functions/getElementId.ts +0 -39
  63. package/src/functions/getElementItem.ts +0 -27
  64. package/src/functions/getElementOrWindow.ts +0 -23
  65. package/src/functions/getExp.ts +0 -21
  66. package/src/functions/getItemByPath.ts +0 -24
  67. package/src/functions/getKey.ts +0 -9
  68. package/src/functions/getLengthOfAllArray.ts +0 -13
  69. package/src/functions/getMaxLengthAllArray.ts +0 -13
  70. package/src/functions/getMinLengthAllArray.ts +0 -13
  71. package/src/functions/getMouseClient.ts +0 -17
  72. package/src/functions/getMouseClientX.ts +0 -9
  73. package/src/functions/getMouseClientY.ts +0 -9
  74. package/src/functions/getObjectByKeys.ts +0 -24
  75. package/src/functions/getObjectNoUndefined.ts +0 -23
  76. package/src/functions/getObjectOrNone.ts +0 -11
  77. package/src/functions/getRandomText.ts +0 -29
  78. package/src/functions/getRequestString.ts +0 -21
  79. package/src/functions/getStepPercent.ts +0 -19
  80. package/src/functions/getStepValue.ts +0 -19
  81. package/src/functions/goScroll.ts +0 -40
  82. package/src/functions/inArray.ts +0 -10
  83. package/src/functions/initScrollbarOffset.ts +0 -14
  84. package/src/functions/intersectKey.ts +0 -34
  85. package/src/functions/isArray.ts +0 -9
  86. package/src/functions/isDifferent.ts +0 -27
  87. package/src/functions/isDomRuntime.ts +0 -12
  88. package/src/functions/isFilled.ts +0 -49
  89. package/src/functions/isFloat.ts +0 -16
  90. package/src/functions/isFunction.ts +0 -11
  91. package/src/functions/isInDom.ts +0 -15
  92. package/src/functions/isIntegerBetween.ts +0 -11
  93. package/src/functions/isNull.ts +0 -11
  94. package/src/functions/isNumber.ts +0 -16
  95. package/src/functions/isObject.ts +0 -9
  96. package/src/functions/isObjectNotArray.ts +0 -11
  97. package/src/functions/isSelected.ts +0 -32
  98. package/src/functions/isSelectedByList.ts +0 -19
  99. package/src/functions/isString.ts +0 -9
  100. package/src/functions/isWindow.ts +0 -11
  101. package/src/functions/random.ts +0 -10
  102. package/src/functions/replaceRecursive.ts +0 -60
  103. package/src/functions/replaceTemplate.ts +0 -22
  104. package/src/functions/secondToTime.ts +0 -20
  105. package/src/functions/setElementItem.ts +0 -56
  106. package/src/functions/setValues.ts +0 -59
  107. package/src/functions/splice.ts +0 -59
  108. package/src/functions/strFill.ts +0 -12
  109. package/src/functions/toArray.ts +0 -19
  110. package/src/functions/toCamelCase.ts +0 -16
  111. package/src/functions/toCamelCaseFirst.ts +0 -12
  112. package/src/functions/toDate.ts +0 -44
  113. package/src/functions/toKebabCase.ts +0 -25
  114. package/src/functions/toNumber.ts +0 -35
  115. package/src/functions/toNumberByMax.ts +0 -33
  116. package/src/functions/toPercent.ts +0 -10
  117. package/src/functions/toPercentBy100.ts +0 -12
  118. package/src/functions/transformation.ts +0 -59
  119. package/src/functions/uniqueArray.ts +0 -9
  120. package/src/functions/writeClipboardData.ts +0 -17
  121. package/src/library.ts +0 -116
  122. package/src/types/apiTypes.ts +0 -143
  123. package/src/types/basicTypes.ts +0 -155
  124. package/src/types/geoTypes.ts +0 -109
  125. package/src/types/metaTypes.ts +0 -764
  126. package/src/vite-env.d.ts +0 -1
@@ -1,836 +0,0 @@
1
- /**
2
- * @vitest-environment jsdom
3
- */
4
-
5
- import { describe, it, expect, beforeEach, afterEach } from 'vitest'
6
- import { MetaManager } from '../MetaManager'
7
-
8
- describe('MetaManager', () => {
9
- let manager: MetaManager<readonly ['description', 'keywords', 'author']>
10
- const metaTags = ['description', 'keywords', 'author'] as const
11
-
12
- beforeEach(() => {
13
- // Очистка DOM перед каждым тестом
14
- document.head.innerHTML = ''
15
-
16
- manager = new MetaManager(metaTags)
17
- })
18
-
19
- afterEach(() => {
20
- // Очистка после тестов
21
- document.head.innerHTML = ''
22
- })
23
-
24
- describe('constructor', () => {
25
- it('should create MetaManager instance', () => {
26
- expect(manager).toBeInstanceOf(MetaManager)
27
- })
28
-
29
- it('should initialize with empty items', () => {
30
- const items = manager.getItems()
31
- expect(items.description).toBe('')
32
- expect(items.keywords).toBe('')
33
- expect(items.author).toBe('')
34
- })
35
-
36
- it('should read existing meta tags from DOM on initialization', () => {
37
- // Создаем мета-теги в DOM перед инициализацией
38
- const descMeta = document.createElement('meta')
39
- descMeta.setAttribute('name', 'description')
40
- descMeta.setAttribute('content', 'Existing description')
41
- document.head.appendChild(descMeta)
42
-
43
- const keywordsMeta = document.createElement('meta')
44
- keywordsMeta.setAttribute('name', 'keywords')
45
- keywordsMeta.setAttribute('content', 'existing, keywords')
46
- document.head.appendChild(keywordsMeta)
47
-
48
- // Создаем новый экземпляр
49
- const newManager = new MetaManager(metaTags)
50
-
51
- // Должен прочитать существующие теги
52
- expect(newManager.get('description')).toBe('Existing description')
53
- expect(newManager.get('keywords')).toBe('existing, keywords')
54
- })
55
-
56
- it('should use "name" attribute by default', () => {
57
- manager.set('description', 'Test')
58
-
59
- const element = document.querySelector('meta[name="description"]')
60
- expect(element).toBeTruthy()
61
- expect(element?.getAttribute('name')).toBe('description')
62
- })
63
-
64
- it('should use "property" attribute when isProperty is true', () => {
65
- const propertyManager = new MetaManager(['og:title', 'og:description'] as const, true)
66
- propertyManager.set('og:title', 'Test Title')
67
-
68
- const element = document.querySelector('meta[property="og:title"]')
69
- expect(element).toBeTruthy()
70
- expect(element?.getAttribute('property')).toBe('og:title')
71
- expect(element?.getAttribute('name')).toBeNull()
72
- })
73
- })
74
-
75
- describe('getListMeta', () => {
76
- it('should return the list of meta tag names', () => {
77
- const list = manager.getListMeta()
78
-
79
- expect(list).toEqual(metaTags)
80
- expect(list.length).toBe(3)
81
- expect(list[0]).toBe('description')
82
- expect(list[1]).toBe('keywords')
83
- expect(list[2]).toBe('author')
84
- })
85
-
86
- it('should return readonly array', () => {
87
- const list = manager.getListMeta()
88
- expect(list).toBe(metaTags) // Должна быть та же ссылка
89
- })
90
- })
91
-
92
- describe('get', () => {
93
- it('should return empty string when meta tag not set', () => {
94
- expect(manager.get('description')).toBe('')
95
- expect(manager.get('keywords')).toBe('')
96
- })
97
-
98
- it('should return meta tag content after setting', () => {
99
- manager.set('description', 'Test description')
100
- expect(manager.get('description')).toBe('Test description')
101
- })
102
-
103
- it('should return different values for different tags', () => {
104
- manager.set('description', 'Description text')
105
- manager.set('keywords', 'key, words')
106
- manager.set('author', 'John Doe')
107
-
108
- expect(manager.get('description')).toBe('Description text')
109
- expect(manager.get('keywords')).toBe('key, words')
110
- expect(manager.get('author')).toBe('John Doe')
111
- })
112
- })
113
-
114
- describe('getItems', () => {
115
- it('should return empty object when no meta tags set', () => {
116
- const items = manager.getItems()
117
-
118
- expect(items.description).toBe('')
119
- expect(items.keywords).toBe('')
120
- expect(items.author).toBe('')
121
- })
122
-
123
- it('should return all meta tags as object', () => {
124
- manager.set('description', 'Desc')
125
- manager.set('keywords', 'key')
126
- manager.set('author', 'Author')
127
-
128
- const items = manager.getItems()
129
-
130
- expect(items).toEqual({
131
- description: 'Desc',
132
- keywords: 'key',
133
- author: 'Author'
134
- })
135
- })
136
-
137
- it('should return reference to internal items', () => {
138
- const items1 = manager.getItems()
139
- const items2 = manager.getItems()
140
-
141
- expect(items1).toBe(items2)
142
- })
143
- })
144
-
145
- describe('set', () => {
146
- it('should set meta tag content', () => {
147
- manager.set('description', 'New description')
148
-
149
- expect(manager.get('description')).toBe('New description')
150
- })
151
-
152
- it('should create meta tag in DOM', () => {
153
- manager.set('description', 'DOM test')
154
-
155
- const element = document.querySelector('meta[name="description"]')
156
- expect(element).toBeTruthy()
157
- expect(element?.getAttribute('content')).toBe('DOM test')
158
- })
159
-
160
- it('should update existing meta tag in DOM', () => {
161
- // Первая установка
162
- manager.set('description', 'First value')
163
-
164
- const firstElements = document.querySelectorAll('meta[name="description"]')
165
- expect(firstElements.length).toBe(1)
166
-
167
- // Обновление
168
- manager.set('description', 'Second value')
169
-
170
- const secondElements = document.querySelectorAll('meta[name="description"]')
171
- expect(secondElements.length).toBe(1) // Не должно создавать дубликат
172
- expect(secondElements?.[0]?.getAttribute('content')).toBe('Second value')
173
- })
174
-
175
- it('should return this for chaining', () => {
176
- const result = manager.set('description', 'Test')
177
- expect(result).toBe(manager)
178
- })
179
-
180
- it('should support method chaining', () => {
181
- manager
182
- .set('description', 'Desc')
183
- .set('keywords', 'keys')
184
- .set('author', 'Author')
185
-
186
- expect(manager.get('description')).toBe('Desc')
187
- expect(manager.get('keywords')).toBe('keys')
188
- expect(manager.get('author')).toBe('Author')
189
- })
190
-
191
- it('should handle empty string', () => {
192
- manager.set('description', '')
193
- expect(manager.get('description')).toBe('')
194
- })
195
-
196
- it('should handle special characters', () => {
197
- manager.set('description', 'Text with "quotes" & <tags>')
198
- expect(manager.get('description')).toBe('Text with "quotes" & <tags>')
199
- })
200
- })
201
-
202
- describe('setByList', () => {
203
- it('should set multiple meta tags at once', () => {
204
- manager.setByList({
205
- description: 'Bulk description',
206
- keywords: 'bulk, keywords',
207
- author: 'Bulk Author'
208
- })
209
-
210
- expect(manager.get('description')).toBe('Bulk description')
211
- expect(manager.get('keywords')).toBe('bulk, keywords')
212
- expect(manager.get('author')).toBe('Bulk Author')
213
- })
214
-
215
- it('should create all meta tags in DOM', () => {
216
- manager.setByList({
217
- description: 'Desc',
218
- keywords: 'keys'
219
- })
220
-
221
- expect(document.querySelector('meta[name="description"]')?.getAttribute('content')).toBe('Desc')
222
- expect(document.querySelector('meta[name="keywords"]')?.getAttribute('content')).toBe('keys')
223
- })
224
-
225
- it('should handle partial updates', () => {
226
- manager.set('description', 'Initial')
227
- manager.set('keywords', 'Initial keys')
228
-
229
- manager.setByList({
230
- description: 'Updated'
231
- })
232
-
233
- expect(manager.get('description')).toBe('Updated')
234
- expect(manager.get('keywords')).toBe('Initial keys') // Не должно измениться
235
- })
236
-
237
- it('should return this for chaining', () => {
238
- const result = manager.setByList({ description: 'Test' })
239
- expect(result).toBe(manager)
240
- })
241
-
242
- it('should handle empty object', () => {
243
- manager.set('description', 'Initial')
244
- manager.setByList({})
245
-
246
- expect(manager.get('description')).toBe('Initial')
247
- })
248
-
249
- it('should convert values to strings', () => {
250
- manager.setByList({
251
- description: 'String value'
252
- })
253
-
254
- expect(manager.get('description')).toBe('String value')
255
- })
256
- })
257
-
258
- describe('html', () => {
259
- it('should return empty string when no meta tags set', () => {
260
- const html = manager.html()
261
- expect(html).toBe('')
262
- })
263
-
264
- it('should generate HTML for single meta tag', () => {
265
- manager.set('description', 'Test description')
266
-
267
- const html = manager.html()
268
- expect(html).toContain('<meta name="description" content="Test description">')
269
- })
270
-
271
- it('should generate HTML for multiple meta tags', () => {
272
- manager.set('description', 'Desc')
273
- manager.set('keywords', 'keys')
274
- manager.set('author', 'Author')
275
-
276
- const html = manager.html()
277
-
278
- expect(html).toContain('name="description"')
279
- expect(html).toContain('content="Desc"')
280
- expect(html).toContain('name="keywords"')
281
- expect(html).toContain('content="keys"')
282
- expect(html).toContain('name="author"')
283
- expect(html).toContain('content="Author"')
284
- })
285
-
286
- it('should escape special characters', () => {
287
- manager.set('description', 'Text with "quotes" & <tags>')
288
-
289
- const html = manager.html()
290
-
291
- expect(html).toContain('&quot;')
292
- expect(html).toContain('&amp;')
293
- expect(html).toContain('&lt;')
294
- expect(html).toContain('&gt;')
295
- })
296
-
297
- it('should not include empty meta tags', () => {
298
- manager.set('description', 'Has content')
299
- manager.set('keywords', '')
300
-
301
- const html = manager.html()
302
-
303
- expect(html).toContain('name="description"')
304
- expect(html).not.toContain('name="keywords"')
305
- })
306
-
307
- it('should use property attribute when isProperty is true', () => {
308
- const propertyManager = new MetaManager(['og:title'] as const, true)
309
- propertyManager.set('og:title', 'Title')
310
-
311
- const html = propertyManager.html()
312
-
313
- expect(html).toContain('property="og:title"')
314
- expect(html).not.toContain('name="og:title"')
315
- })
316
-
317
- it('should generate valid HTML string', () => {
318
- manager.set('description', 'Test')
319
-
320
- const html = manager.html()
321
-
322
- expect(html).toMatch(/<meta [^>]+>/)
323
- })
324
- })
325
-
326
- describe('getAttributeName', () => {
327
- it('should return "name" by default', () => {
328
- expect(manager['getAttributeName']()).toBe('name')
329
- })
330
-
331
- it('should return "property" when isProperty is true', () => {
332
- const propertyManager = new MetaManager(['og:title'] as const, true)
333
- expect(propertyManager['getAttributeName']()).toBe('property')
334
- })
335
- })
336
-
337
- describe('findMetaElement', () => {
338
- it('should find existing meta element by name', () => {
339
- const meta = document.createElement('meta')
340
- meta.setAttribute('name', 'description')
341
- meta.setAttribute('content', 'Test')
342
- document.head.appendChild(meta)
343
-
344
- const found = (manager as any).findMetaElement('description')
345
-
346
- expect(found).toBeTruthy()
347
- expect(found?.getAttribute('content')).toBe('Test')
348
- })
349
-
350
- it('should find meta element by property when isProperty is true', () => {
351
- const propertyManager = new MetaManager(['og:title'] as const, true)
352
-
353
- const meta = document.createElement('meta')
354
- meta.setAttribute('property', 'og:title')
355
- meta.setAttribute('content', 'Title')
356
- document.head.appendChild(meta)
357
-
358
- const found = (propertyManager as any).findMetaElement('og:title')
359
-
360
- expect(found).toBeTruthy()
361
- expect(found?.getAttribute('content')).toBe('Title')
362
- })
363
-
364
- it('should return undefined when element not found', () => {
365
- const found = (manager as any).findMetaElement('nonexistent')
366
-
367
- expect(found).toBeUndefined()
368
- })
369
- })
370
-
371
- describe('edge cases', () => {
372
- it('should handle very long content', () => {
373
- const longContent = 'a'.repeat(10000)
374
- manager.set('description', longContent)
375
-
376
- expect(manager.get('description')).toBe(longContent)
377
- })
378
-
379
- it('should handle unicode characters', () => {
380
- manager.set('description', 'Описание на русском 🎉')
381
- manager.set('keywords', '中文, 日本語, 한국어')
382
-
383
- expect(manager.get('description')).toBe('Описание на русском 🎉')
384
- expect(manager.get('keywords')).toBe('中文, 日本語, 한국어')
385
- })
386
-
387
- it('should handle HTML entities', () => {
388
- manager.set('description', '&lt;script&gt;alert("XSS")&lt;/script&gt;')
389
-
390
- expect(manager.get('description')).toBe('&lt;script&gt;alert("XSS")&lt;/script&gt;')
391
- })
392
-
393
- it('should handle newlines and tabs', () => {
394
- manager.set('description', 'Line 1\nLine 2\tTabbed')
395
-
396
- expect(manager.get('description')).toBe('Line 1\nLine 2\tTabbed')
397
- })
398
-
399
- it('should handle multiple consecutive updates', () => {
400
- for (let i = 0; i < 100; i++) {
401
- manager.set('description', `Value ${i}`)
402
- }
403
-
404
- expect(manager.get('description')).toBe('Value 99')
405
-
406
- // Должен быть только один элемент в DOM
407
- const elements = document.querySelectorAll('meta[name="description"]')
408
- expect(elements.length).toBe(1)
409
- })
410
- })
411
-
412
- describe('DOM synchronization', () => {
413
- it('should keep internal state and DOM in sync', () => {
414
- manager.set('description', 'Sync test')
415
-
416
- const domContent = document.querySelector('meta[name="description"]')?.getAttribute('content')
417
- const internalContent = manager.get('description')
418
-
419
- expect(domContent).toBe(internalContent)
420
- })
421
-
422
- it('should update DOM when updating existing meta tag', () => {
423
- manager.set('description', 'First')
424
- manager.set('description', 'Second')
425
- manager.set('description', 'Third')
426
-
427
- const elements = document.querySelectorAll('meta[name="description"]')
428
- expect(elements.length).toBe(1)
429
- expect(elements?.[0]?.getAttribute('content')).toBe('Third')
430
- })
431
-
432
- it('should not create duplicate tags', () => {
433
- // Создаем существующий тег
434
- const existingMeta = document.createElement('meta')
435
- existingMeta.setAttribute('name', 'description')
436
- existingMeta.setAttribute('content', 'Existing')
437
- document.head.appendChild(existingMeta)
438
-
439
- // Создаем менеджер и обновляем
440
- const newManager = new MetaManager(metaTags)
441
- newManager.set('description', 'Updated')
442
-
443
- const elements = document.querySelectorAll('meta[name="description"]')
444
- expect(elements.length).toBe(1)
445
- expect(elements?.[0]?.getAttribute('content')).toBe('Updated')
446
- })
447
- })
448
-
449
- describe('SSR compatibility', () => {
450
- it('should generate valid HTML for server-side rendering', () => {
451
- manager
452
- .set('description', 'SSR Description')
453
- .set('keywords', 'ssr, test')
454
- .set('author', 'SSR Author')
455
-
456
- const html = manager.html()
457
-
458
- // HTML должен быть валидным
459
- expect(html).toMatch(/<meta [^>]+>/g)
460
-
461
- // Должен содержать все теги
462
- expect(html.split('<meta').length - 1).toBe(3)
463
- })
464
-
465
- it('should properly escape content for HTML', () => {
466
- manager.set('description', 'Test "quotes" & <html> entities')
467
-
468
- const html = manager.html()
469
-
470
- // HTML должен быть безопасным
471
- expect(html).not.toContain('"quotes"')
472
- expect(html).toContain('&quot;quotes&quot;')
473
- expect(html).not.toContain('<html>')
474
- expect(html).toContain('&lt;html&gt;')
475
- })
476
- })
477
-
478
- describe('TypeScript types', () => {
479
- it('should only allow setting defined meta tags', () => {
480
- // Эти должны работать
481
- manager.set('description', 'test')
482
- manager.set('keywords', 'test')
483
- manager.set('author', 'test')
484
-
485
- expect(manager.get('description')).toBe('test')
486
- })
487
-
488
- it('should have correct return types', () => {
489
- const getString: string = manager.get('description')
490
- const getItems: { description?: string, keywords?: string, author?: string } = manager.getItems()
491
- const getList: readonly ['description', 'keywords', 'author'] = manager.getListMeta()
492
- const setReturn: MetaManager<readonly ['description', 'keywords', 'author']> = manager.set('description', 'test')
493
- const htmlReturn: string = manager.html()
494
-
495
- expect(typeof getString).toBe('string')
496
- expect(typeof getItems).toBe('object')
497
- expect(Array.isArray(getList)).toBe(true)
498
- expect(setReturn).toBeInstanceOf(MetaManager)
499
- expect(typeof htmlReturn).toBe('string')
500
- })
501
- })
502
-
503
- describe('integration scenarios', () => {
504
- it('should work with complex real-world scenario', () => {
505
- // Инициализация с существующими тегами
506
- const initialDesc = document.createElement('meta')
507
- initialDesc.setAttribute('name', 'description')
508
- initialDesc.setAttribute('content', 'Initial page description')
509
- document.head.appendChild(initialDesc)
510
-
511
- // Создание менеджера
512
- const pageManager = new MetaManager(['description', 'keywords', 'author', 'robots'] as const)
513
-
514
- // Массовое обновление
515
- pageManager.setByList({
516
- description: 'Updated description',
517
- keywords: 'web, development, javascript',
518
- author: 'John Doe',
519
- robots: 'index, follow'
520
- })
521
-
522
- // Проверка внутреннего состояния
523
- expect(pageManager.get('description')).toBe('Updated description')
524
- expect(pageManager.get('keywords')).toBe('web, development, javascript')
525
-
526
- // Проверка DOM
527
- expect(document.querySelector('meta[name="description"]')?.getAttribute('content'))
528
- .toBe('Updated description')
529
-
530
- // Генерация HTML для SSR
531
- const html = pageManager.html()
532
- expect(html).toContain('name="description"')
533
- expect(html).toContain('name="keywords"')
534
- expect(html).toContain('name="author"')
535
- expect(html).toContain('name="robots"')
536
-
537
- // Количество тегов в DOM должно соответствовать
538
- const metaTags = document.querySelectorAll('meta[name]')
539
- expect(metaTags.length).toBe(4)
540
- })
541
- })
542
-
543
- describe('SSR environment (without DOM)', () => {
544
- it('should work without DOM runtime', () => {
545
- // Сохраняем оригинальные глобальные объекты
546
- const originalDocument = globalThis.document
547
- const originalWindow = globalThis.window
548
-
549
- // Удаляем document и window для эмуляции SSR окружения
550
- delete (globalThis as any).document
551
- delete (globalThis as any).window
552
-
553
- try {
554
- // Создание менеджера без DOM
555
- const ssrManager = new MetaManager(['description', 'keywords', 'author'] as const)
556
-
557
- // Установка значений должна работать
558
- ssrManager.set('description', 'SSR Description')
559
- ssrManager.set('keywords', 'ssr, test, server')
560
- ssrManager.set('author', 'SSR Author')
561
-
562
- // Внутреннее состояние должно обновляться
563
- expect(ssrManager.get('description')).toBe('SSR Description')
564
- expect(ssrManager.get('keywords')).toBe('ssr, test, server')
565
- expect(ssrManager.get('author')).toBe('SSR Author')
566
-
567
- // Массовое обновление должно работать
568
- ssrManager.setByList({
569
- description: 'Updated SSR Description',
570
- keywords: 'updated, ssr'
571
- })
572
-
573
- expect(ssrManager.get('description')).toBe('Updated SSR Description')
574
- expect(ssrManager.get('keywords')).toBe('updated, ssr')
575
-
576
- // Генерация HTML должна работать
577
- const html = ssrManager.html()
578
- expect(html).toBeTruthy()
579
- expect(html).toContain('name="description"')
580
- expect(html).toContain('content="Updated SSR Description"')
581
- expect(html).toContain('name="keywords"')
582
- expect(html).toContain('content="updated, ssr"')
583
- expect(html).toContain('name="author"')
584
- expect(html).toContain('content="SSR Author"')
585
- } finally {
586
- // Восстанавливаем глобальные объекты
587
- if (originalDocument) {
588
- (globalThis as any).document = originalDocument
589
- }
590
- if (originalWindow) {
591
- (globalThis as any).window = originalWindow
592
- }
593
- }
594
- })
595
-
596
- it('should generate valid HTML in SSR mode', () => {
597
- const originalDocument = globalThis.document
598
- delete (globalThis as any).document
599
-
600
- try {
601
- const ssrManager = new MetaManager(['description', 'keywords', 'robots'] as const)
602
-
603
- ssrManager.setByList({
604
- description: 'Server-side rendered page',
605
- keywords: 'ssr, node, server',
606
- robots: 'index, follow'
607
- })
608
-
609
- const html = ssrManager.html()
610
-
611
- // Проверяем валидность HTML
612
- expect(html).toMatch(/<meta name="[^"]+" content="[^"]+">/)
613
-
614
- // Проверяем количество тегов
615
- const metaTagsCount = (html.match(/<meta/g) || []).length
616
- expect(metaTagsCount).toBe(3)
617
-
618
- // Проверяем структуру каждого тега
619
- expect(html).toContain('<meta name="description" content="Server-side rendered page">')
620
- expect(html).toContain('<meta name="keywords" content="ssr, node, server">')
621
- expect(html).toContain('<meta name="robots" content="index, follow">')
622
- } finally {
623
- if (originalDocument) {
624
- (globalThis as any).document = originalDocument
625
- }
626
- }
627
- })
628
-
629
- it('should handle special characters in SSR mode', () => {
630
- const originalDocument = globalThis.document
631
- delete (globalThis as any).document
632
-
633
- try {
634
- const ssrManager = new MetaManager(['description'] as const)
635
-
636
- ssrManager.set('description', 'Test with "quotes" & <html> tags')
637
-
638
- const html = ssrManager.html()
639
-
640
- // Должно экранировать спецсимволы
641
- expect(html).toContain('&quot;')
642
- expect(html).toContain('&amp;')
643
- expect(html).toContain('&lt;')
644
- expect(html).toContain('&gt;')
645
-
646
- // Не должно содержать неэкранированные символы
647
- expect(html).not.toContain('"quotes"')
648
- expect(html).not.toContain('& <html>')
649
- } finally {
650
- if (originalDocument) {
651
- (globalThis as any).document = originalDocument
652
- }
653
- }
654
- })
655
-
656
- it('should support property attribute in SSR mode', () => {
657
- const originalDocument = globalThis.document
658
- delete (globalThis as any).document
659
-
660
- try {
661
- const ogManager = new MetaManager(['og:title', 'og:description'] as const, true)
662
-
663
- ogManager.set('og:title', 'Open Graph Title')
664
- ogManager.set('og:description', 'Open Graph Description')
665
-
666
- const html = ogManager.html()
667
-
668
- // Должен использовать property вместо name
669
- expect(html).toContain('property="og:title"')
670
- expect(html).toContain('property="og:description"')
671
- expect(html).not.toContain('name="og:title"')
672
-
673
- // Проверяем контент
674
- expect(html).toContain('content="Open Graph Title"')
675
- expect(html).toContain('content="Open Graph Description"')
676
- } finally {
677
- if (originalDocument) {
678
- (globalThis as any).document = originalDocument
679
- }
680
- }
681
- })
682
-
683
- it('should not break when trying to update DOM in SSR', () => {
684
- const originalDocument = globalThis.document
685
- delete (globalThis as any).document
686
-
687
- try {
688
- const ssrManager = new MetaManager(['description'] as const)
689
-
690
- // Не должно вызывать ошибку
691
- expect(() => {
692
- ssrManager.set('description', 'Test')
693
- }).not.toThrow()
694
-
695
- // Внутреннее состояние должно обновиться
696
- expect(ssrManager.get('description')).toBe('Test')
697
-
698
- // HTML должен генерироваться
699
- const html = ssrManager.html()
700
- expect(html).toContain('content="Test"')
701
- } finally {
702
- if (originalDocument) {
703
- (globalThis as any).document = originalDocument
704
- }
705
- }
706
- })
707
-
708
- it('should work with getItems in SSR mode', () => {
709
- const originalDocument = globalThis.document
710
- delete (globalThis as any).document
711
-
712
- try {
713
- const ssrManager = new MetaManager(['description', 'keywords'] as const)
714
-
715
- ssrManager.setByList({
716
- description: 'SSR Items Test',
717
- keywords: 'test, items'
718
- })
719
-
720
- const items = ssrManager.getItems()
721
-
722
- expect(items).toEqual({
723
- description: 'SSR Items Test',
724
- keywords: 'test, items'
725
- })
726
- } finally {
727
- if (originalDocument) {
728
- (globalThis as any).document = originalDocument
729
- }
730
- }
731
- })
732
-
733
- it('should initialize with empty values in SSR mode', () => {
734
- const originalDocument = globalThis.document
735
- delete (globalThis as any).document
736
-
737
- try {
738
- const ssrManager = new MetaManager(['description', 'keywords', 'author'] as const)
739
-
740
- // Все должно быть пустым при инициализации
741
- expect(ssrManager.get('description')).toBe('')
742
- expect(ssrManager.get('keywords')).toBe('')
743
- expect(ssrManager.get('author')).toBe('')
744
-
745
- const items = ssrManager.getItems()
746
- expect(items.description).toBe('')
747
- expect(items.keywords).toBe('')
748
- expect(items.author).toBe('')
749
- } finally {
750
- if (originalDocument) {
751
- (globalThis as any).document = originalDocument
752
- }
753
- }
754
- })
755
-
756
- it('should support chaining in SSR mode', () => {
757
- const originalDocument = globalThis.document
758
- delete (globalThis as any).document
759
-
760
- try {
761
- const ssrManager = new MetaManager(['description', 'keywords', 'author'] as const)
762
-
763
- const result = ssrManager
764
- .set('description', 'SSR Chain')
765
- .set('keywords', 'chain, test')
766
- .setByList({ author: 'Chain Author' })
767
-
768
- expect(result).toBe(ssrManager)
769
- expect(ssrManager.get('description')).toBe('SSR Chain')
770
- expect(ssrManager.get('keywords')).toBe('chain, test')
771
- expect(ssrManager.get('author')).toBe('Chain Author')
772
- } finally {
773
- if (originalDocument) {
774
- (globalThis as any).document = originalDocument
775
- }
776
- }
777
- })
778
-
779
- it('should handle complete SSR workflow', () => {
780
- const originalDocument = globalThis.document
781
- delete (globalThis as any).document
782
-
783
- try {
784
- // Создание менеджера на сервере
785
- const ssrManager = new MetaManager(
786
- ['description', 'keywords', 'author', 'robots', 'viewport'] as const
787
- )
788
-
789
- // Настройка мета-тегов
790
- ssrManager.setByList({
791
- description: 'Complete SSR page description',
792
- keywords: 'ssr, server, node, express',
793
- author: 'Server Admin',
794
- robots: 'index, follow',
795
- viewport: 'width=device-width, initial-scale=1'
796
- })
797
-
798
- // Генерация HTML для вставки в шаблон
799
- const metaTags = ssrManager.html()
800
-
801
- // Проверяем, что HTML готов для SSR
802
- expect(metaTags).toBeTruthy()
803
- expect(typeof metaTags).toBe('string')
804
-
805
- // Проверяем наличие всех тегов
806
- expect(metaTags).toContain('name="description"')
807
- expect(metaTags).toContain('name="keywords"')
808
- expect(metaTags).toContain('name="author"')
809
- expect(metaTags).toContain('name="robots"')
810
- expect(metaTags).toContain('name="viewport"')
811
-
812
- // Проверяем, что можно вставить в HTML шаблон
813
- const htmlTemplate = `
814
- <!DOCTYPE html>
815
- <html>
816
- <head>
817
- <meta charset="UTF-8">
818
- ${metaTags}
819
- <title>SSR Page</title>
820
- </head>
821
- <body>
822
- <h1>Server-side rendered content</h1>
823
- </body>
824
- </html>
825
- `
826
-
827
- expect(htmlTemplate).toContain('<meta name="description"')
828
- expect(htmlTemplate).toContain('Complete SSR page description')
829
- } finally {
830
- if (originalDocument) {
831
- (globalThis as any).document = originalDocument
832
- }
833
- }
834
- })
835
- })
836
- })