@dxtmisha/functional-basic 0.1.0 → 0.1.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.
- package/package.json +5 -3
- package/src/classes/Api.ts +407 -0
- package/src/classes/ApiDefault.ts +83 -0
- package/src/classes/ApiHeaders.ts +52 -0
- package/src/classes/ApiPreparation.ts +114 -0
- package/src/classes/ApiResponse.ts +293 -0
- package/src/classes/ApiStatus.ts +173 -0
- package/src/classes/BroadcastMessage.ts +73 -0
- package/src/classes/Cache.ts +60 -0
- package/src/classes/CacheItem.ts +95 -0
- package/src/classes/CacheStatic.ts +30 -0
- package/src/classes/Cookie.ts +135 -0
- package/src/classes/CookieBlock.ts +31 -0
- package/src/classes/DataStorage.ts +194 -0
- package/src/classes/Datetime.ts +891 -0
- package/src/classes/EventItem.ts +373 -0
- package/src/classes/Geo.ts +320 -0
- package/src/classes/GeoFlag.ts +386 -0
- package/src/classes/GeoIntl.ts +839 -0
- package/src/classes/GeoPhone.ts +272 -0
- package/src/classes/Global.ts +32 -0
- package/src/classes/Hash.ts +142 -0
- package/src/classes/Icons.ts +165 -0
- package/src/classes/Loading.ts +90 -0
- package/src/classes/Meta.ts +284 -0
- package/src/classes/MetaManager.ts +200 -0
- package/src/classes/MetaOg.ts +147 -0
- package/src/classes/MetaTwitter.ts +154 -0
- package/src/classes/ScrollbarWidth.ts +86 -0
- package/src/classes/Translate.ts +293 -0
- package/src/classes/__tests__/Api.test.ts +728 -0
- package/src/classes/__tests__/ApiDefault.test.ts +222 -0
- package/src/classes/__tests__/ApiHeaders.test.ts +447 -0
- package/src/classes/__tests__/ApiPreparation.test.ts +257 -0
- package/src/classes/__tests__/ApiResponse.test.ts +547 -0
- package/src/classes/__tests__/ApiStatus.test.ts +403 -0
- package/src/classes/__tests__/Meta.test.ts +629 -0
- package/src/classes/__tests__/MetaManager.test.ts +836 -0
- package/src/classes/__tests__/MetaOg.test.ts +677 -0
- package/src/classes/__tests__/MetaTwitter.test.ts +423 -0
- package/src/functions/anyToString.ts +36 -0
- package/src/functions/applyTemplate.ts +63 -0
- package/src/functions/arrFill.ts +10 -0
- package/src/functions/copyObject.ts +10 -0
- package/src/functions/createElement.ts +40 -0
- package/src/functions/domQuerySelector.ts +15 -0
- package/src/functions/domQuerySelectorAll.ts +15 -0
- package/src/functions/encodeAttribute.ts +15 -0
- package/src/functions/eventStopPropagation.ts +10 -0
- package/src/functions/executeFunction.ts +13 -0
- package/src/functions/executePromise.ts +19 -0
- package/src/functions/forEach.ts +39 -0
- package/src/functions/frame.ts +38 -0
- package/src/functions/getAttributes.ts +27 -0
- package/src/functions/getClipboardData.ts +13 -0
- package/src/functions/getColumn.ts +18 -0
- package/src/functions/getElement.ts +35 -0
- package/src/functions/getElementId.ts +39 -0
- package/src/functions/getElementItem.ts +27 -0
- package/src/functions/getElementOrWindow.ts +23 -0
- package/src/functions/getExp.ts +21 -0
- package/src/functions/getItemByPath.ts +24 -0
- package/src/functions/getKey.ts +9 -0
- package/src/functions/getLengthOfAllArray.ts +13 -0
- package/src/functions/getMaxLengthAllArray.ts +13 -0
- package/src/functions/getMinLengthAllArray.ts +13 -0
- package/src/functions/getMouseClient.ts +17 -0
- package/src/functions/getMouseClientX.ts +9 -0
- package/src/functions/getMouseClientY.ts +9 -0
- package/src/functions/getObjectByKeys.ts +24 -0
- package/src/functions/getObjectNoUndefined.ts +23 -0
- package/src/functions/getObjectOrNone.ts +11 -0
- package/src/functions/getRandomText.ts +29 -0
- package/src/functions/getRequestString.ts +21 -0
- package/src/functions/getStepPercent.ts +19 -0
- package/src/functions/getStepValue.ts +19 -0
- package/src/functions/goScroll.ts +40 -0
- package/src/functions/inArray.ts +10 -0
- package/src/functions/initScrollbarOffset.ts +14 -0
- package/src/functions/intersectKey.ts +34 -0
- package/src/functions/isArray.ts +9 -0
- package/src/functions/isDifferent.ts +27 -0
- package/src/functions/isDomRuntime.ts +12 -0
- package/src/functions/isFilled.ts +49 -0
- package/src/functions/isFloat.ts +16 -0
- package/src/functions/isFunction.ts +11 -0
- package/src/functions/isInDom.ts +15 -0
- package/src/functions/isIntegerBetween.ts +11 -0
- package/src/functions/isNull.ts +11 -0
- package/src/functions/isNumber.ts +16 -0
- package/src/functions/isObject.ts +9 -0
- package/src/functions/isObjectNotArray.ts +11 -0
- package/src/functions/isSelected.ts +32 -0
- package/src/functions/isSelectedByList.ts +19 -0
- package/src/functions/isString.ts +9 -0
- package/src/functions/isWindow.ts +11 -0
- package/src/functions/random.ts +10 -0
- package/src/functions/replaceRecursive.ts +60 -0
- package/src/functions/replaceTemplate.ts +22 -0
- package/src/functions/secondToTime.ts +20 -0
- package/src/functions/setElementItem.ts +56 -0
- package/src/functions/setValues.ts +59 -0
- package/src/functions/splice.ts +59 -0
- package/src/functions/strFill.ts +12 -0
- package/src/functions/toArray.ts +19 -0
- package/src/functions/toCamelCase.ts +16 -0
- package/src/functions/toCamelCaseFirst.ts +12 -0
- package/src/functions/toDate.ts +44 -0
- package/src/functions/toKebabCase.ts +25 -0
- package/src/functions/toNumber.ts +35 -0
- package/src/functions/toNumberByMax.ts +33 -0
- package/src/functions/toPercent.ts +10 -0
- package/src/functions/toPercentBy100.ts +12 -0
- package/src/functions/transformation.ts +59 -0
- package/src/functions/uniqueArray.ts +9 -0
- package/src/functions/writeClipboardData.ts +17 -0
- package/src/library.ts +116 -0
- package/src/types/apiTypes.ts +143 -0
- package/src/types/basicTypes.ts +155 -0
- package/src/types/geoTypes.ts +109 -0
- package/src/types/metaTypes.ts +764 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
6
|
+
import { Meta } from '../Meta'
|
|
7
|
+
import { MetaRobots } from '../../types/metaTypes'
|
|
8
|
+
|
|
9
|
+
describe('Meta', () => {
|
|
10
|
+
let meta: Meta
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// Очистка DOM перед каждым тестом
|
|
14
|
+
document.head.innerHTML = ''
|
|
15
|
+
document.title = ''
|
|
16
|
+
|
|
17
|
+
meta = new Meta()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
// Очистка после тестов
|
|
22
|
+
document.head.innerHTML = ''
|
|
23
|
+
document.title = ''
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('constructor', () => {
|
|
27
|
+
it('should create Meta instance', () => {
|
|
28
|
+
expect(meta).toBeInstanceOf(Meta)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should initialize MetaOg instance', () => {
|
|
32
|
+
expect(meta.getOg()).toBeDefined()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should initialize MetaTwitter instance', () => {
|
|
36
|
+
expect(meta.getTwitter()).toBeDefined()
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('getTitle', () => {
|
|
41
|
+
it('should return empty string when title is not set', () => {
|
|
42
|
+
expect(meta.getTitle()).toBe('')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should return title without suffix', () => {
|
|
46
|
+
meta.setSuffix('My Site')
|
|
47
|
+
meta.setTitle('Home Page')
|
|
48
|
+
|
|
49
|
+
expect(meta.getTitle()).toBe('Home Page')
|
|
50
|
+
expect(document.title).toBe('Home Page - My Site')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should return title when no suffix is set', () => {
|
|
54
|
+
meta.setTitle('Simple Title')
|
|
55
|
+
|
|
56
|
+
expect(meta.getTitle()).toBe('Simple Title')
|
|
57
|
+
expect(document.title).toBe('Simple Title')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should correctly extract title when suffix changes', () => {
|
|
61
|
+
meta.setSuffix('Old Site')
|
|
62
|
+
meta.setTitle('Page')
|
|
63
|
+
expect(document.title).toBe('Page - Old Site')
|
|
64
|
+
|
|
65
|
+
meta.setSuffix('New Site')
|
|
66
|
+
meta.setTitle('Page')
|
|
67
|
+
expect(document.title).toBe('Page - New Site')
|
|
68
|
+
expect(meta.getTitle()).toBe('Page')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('should handle empty suffix', () => {
|
|
72
|
+
meta.setSuffix('')
|
|
73
|
+
meta.setTitle('No Suffix Title')
|
|
74
|
+
|
|
75
|
+
expect(meta.getTitle()).toBe('No Suffix Title')
|
|
76
|
+
expect(document.title).toBe('No Suffix Title')
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe('getKeywords', () => {
|
|
81
|
+
it('should return empty string when keywords not set', () => {
|
|
82
|
+
expect(meta.getKeywords()).toBe('')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('should return keywords after setting', () => {
|
|
86
|
+
meta.setKeywords('web, javascript, vue')
|
|
87
|
+
expect(meta.getKeywords()).toBe('web, javascript, vue')
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('getDescription', () => {
|
|
92
|
+
it('should return empty string when description not set', () => {
|
|
93
|
+
expect(meta.getDescription()).toBe('')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('should return description after setting', () => {
|
|
97
|
+
meta.setDescription('Test description')
|
|
98
|
+
expect(meta.getDescription()).toBe('Test description')
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
describe('getImage', () => {
|
|
103
|
+
it('should return empty string when image not set', () => {
|
|
104
|
+
expect(meta.getImage()).toBe('')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should return image URL from Open Graph', () => {
|
|
108
|
+
meta.setImage('https://example.com/image.jpg')
|
|
109
|
+
expect(meta.getImage()).toBe('https://example.com/image.jpg')
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe('getCanonical', () => {
|
|
114
|
+
it('should return empty string when canonical not set', () => {
|
|
115
|
+
expect(meta.getCanonical()).toBe('')
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('should return canonical URL after setting', () => {
|
|
119
|
+
meta.setCanonical('https://example.com/page')
|
|
120
|
+
expect(meta.getCanonical()).toBe('https://example.com/page')
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('getRobots', () => {
|
|
125
|
+
it('should return empty string when robots not set', () => {
|
|
126
|
+
expect(meta.getRobots()).toBe('')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('should return robots directive after setting', () => {
|
|
130
|
+
meta.setRobots(MetaRobots.indexFollow)
|
|
131
|
+
expect(meta.getRobots()).toBe(MetaRobots.indexFollow)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe('getAuthor', () => {
|
|
136
|
+
it('should return empty string when author not set', () => {
|
|
137
|
+
expect(meta.getAuthor()).toBe('')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('should return author after setting', () => {
|
|
141
|
+
meta.setAuthor('John Doe')
|
|
142
|
+
expect(meta.getAuthor()).toBe('John Doe')
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
describe('getSiteName', () => {
|
|
147
|
+
it('should return empty string when site name not set', () => {
|
|
148
|
+
expect(meta.getSiteName()).toBe('')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('should return site name from Open Graph', () => {
|
|
152
|
+
meta.setSiteName('My Website')
|
|
153
|
+
expect(meta.getSiteName()).toBe('My Website')
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
describe('getLocale', () => {
|
|
158
|
+
it('should return empty string when locale not set', () => {
|
|
159
|
+
expect(meta.getLocale()).toBe('')
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('should return locale from Open Graph', () => {
|
|
163
|
+
meta.setLocale('en_US')
|
|
164
|
+
expect(meta.getLocale()).toBe('en_US')
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
describe('setTitle', () => {
|
|
169
|
+
it('should set document title', () => {
|
|
170
|
+
meta.setTitle('Test Title')
|
|
171
|
+
expect(document.title).toBe('Test Title')
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('should set title with suffix', () => {
|
|
175
|
+
meta.setSuffix('Site Name')
|
|
176
|
+
meta.setTitle('Page Title')
|
|
177
|
+
|
|
178
|
+
expect(document.title).toBe('Page Title - Site Name')
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('should update Open Graph title with suffix', () => {
|
|
182
|
+
meta.setSuffix('My Site')
|
|
183
|
+
meta.setTitle('OG Test')
|
|
184
|
+
|
|
185
|
+
expect(meta.getOg().getTitle()).toBe('OG Test - My Site')
|
|
186
|
+
expect(document.title).toBe('OG Test - My Site')
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('should update Twitter Card title with suffix', () => {
|
|
190
|
+
meta.setSuffix('My Site')
|
|
191
|
+
meta.setTitle('Twitter Test')
|
|
192
|
+
|
|
193
|
+
expect(meta.getTwitter().getTitle()).toBe('Twitter Test - My Site')
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should update both OG and Twitter with same title', () => {
|
|
197
|
+
meta.setTitle('Shared Title')
|
|
198
|
+
|
|
199
|
+
expect(meta.getOg().getTitle()).toBe('Shared Title')
|
|
200
|
+
expect(meta.getTwitter().getTitle()).toBe('Shared Title')
|
|
201
|
+
expect(document.title).toBe('Shared Title')
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('should return this for chaining', () => {
|
|
205
|
+
const result = meta.setTitle('Test')
|
|
206
|
+
expect(result).toBe(meta)
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
describe('setKeywords', () => {
|
|
211
|
+
it('should set keywords from string', () => {
|
|
212
|
+
meta.setKeywords('web, dev, js')
|
|
213
|
+
expect(meta.getKeywords()).toBe('web, dev, js')
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it('should set keywords from array', () => {
|
|
217
|
+
meta.setKeywords(['web', 'dev', 'js'])
|
|
218
|
+
expect(meta.getKeywords()).toBe('web, dev, js')
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('should create meta tag in DOM', () => {
|
|
222
|
+
meta.setKeywords('test, keywords')
|
|
223
|
+
|
|
224
|
+
const metaTag = document.querySelector('meta[name="keywords"]')
|
|
225
|
+
expect(metaTag).toBeTruthy()
|
|
226
|
+
expect(metaTag?.getAttribute('content')).toBe('test, keywords')
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
it('should return this for chaining', () => {
|
|
230
|
+
const result = meta.setKeywords('test')
|
|
231
|
+
expect(result).toBe(meta)
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
describe('setDescription', () => {
|
|
236
|
+
it('should set description', () => {
|
|
237
|
+
meta.setDescription('Test description')
|
|
238
|
+
expect(meta.getDescription()).toBe('Test description')
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('should create meta tag in DOM', () => {
|
|
242
|
+
meta.setDescription('DOM test')
|
|
243
|
+
|
|
244
|
+
const metaTag = document.querySelector('meta[name="description"]')
|
|
245
|
+
expect(metaTag).toBeTruthy()
|
|
246
|
+
expect(metaTag?.getAttribute('content')).toBe('DOM test')
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('should not sync description to OG or Twitter automatically', () => {
|
|
250
|
+
meta.setDescription('Standard description')
|
|
251
|
+
|
|
252
|
+
// setDescription не синхронизирует с OG и Twitter
|
|
253
|
+
expect(meta.getDescription()).toBe('Standard description')
|
|
254
|
+
expect(meta.getOg().getDescription()).toBe('')
|
|
255
|
+
expect(meta.getTwitter().getDescription()).toBe('')
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
it('should return this for chaining', () => {
|
|
259
|
+
const result = meta.setDescription('test')
|
|
260
|
+
expect(result).toBe(meta)
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
describe('setImage', () => {
|
|
265
|
+
it('should set image for Open Graph', () => {
|
|
266
|
+
meta.setImage('https://example.com/og.jpg')
|
|
267
|
+
expect(meta.getOg().getImage()).toBe('https://example.com/og.jpg')
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
it('should set image for Twitter Card', () => {
|
|
271
|
+
meta.setImage('https://example.com/twitter.jpg')
|
|
272
|
+
expect(meta.getTwitter().getImage()).toBe('https://example.com/twitter.jpg')
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('should return this for chaining', () => {
|
|
276
|
+
const result = meta.setImage('test.jpg')
|
|
277
|
+
expect(result).toBe(meta)
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
describe('setCanonical', () => {
|
|
282
|
+
it('should set canonical URL', () => {
|
|
283
|
+
meta.setCanonical('https://example.com/page')
|
|
284
|
+
expect(meta.getCanonical()).toBe('https://example.com/page')
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
it('should update Open Graph URL', () => {
|
|
288
|
+
meta.setCanonical('https://example.com/og-page')
|
|
289
|
+
expect(meta.getOg().getUrl()).toBe('https://example.com/og-page')
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it('should update Twitter Card URL', () => {
|
|
293
|
+
meta.setCanonical('https://example.com/twitter-page')
|
|
294
|
+
expect(meta.getTwitter().getUrl()).toBe('https://example.com/twitter-page')
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('should return this for chaining', () => {
|
|
298
|
+
const result = meta.setCanonical('https://example.com')
|
|
299
|
+
expect(result).toBe(meta)
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
describe('setRobots', () => {
|
|
304
|
+
it('should set robots directive', () => {
|
|
305
|
+
meta.setRobots(MetaRobots.noIndexNoFollow)
|
|
306
|
+
expect(meta.getRobots()).toBe(MetaRobots.noIndexNoFollow)
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
it('should create robots meta tag in DOM', () => {
|
|
310
|
+
meta.setRobots(MetaRobots.indexFollow)
|
|
311
|
+
|
|
312
|
+
const metaTag = document.querySelector('meta[name="robots"]')
|
|
313
|
+
expect(metaTag).toBeTruthy()
|
|
314
|
+
expect(metaTag?.getAttribute('content')).toBe('index, follow')
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('should return this for chaining', () => {
|
|
318
|
+
const result = meta.setRobots(MetaRobots.indexFollow)
|
|
319
|
+
expect(result).toBe(meta)
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
describe('setAuthor', () => {
|
|
324
|
+
it('should set author', () => {
|
|
325
|
+
meta.setAuthor('Jane Doe')
|
|
326
|
+
expect(meta.getAuthor()).toBe('Jane Doe')
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
it('should create author meta tag in DOM', () => {
|
|
330
|
+
meta.setAuthor('John Smith')
|
|
331
|
+
|
|
332
|
+
const metaTag = document.querySelector('meta[name="author"]')
|
|
333
|
+
expect(metaTag).toBeTruthy()
|
|
334
|
+
expect(metaTag?.getAttribute('content')).toBe('John Smith')
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('should return this for chaining', () => {
|
|
338
|
+
const result = meta.setAuthor('Test')
|
|
339
|
+
expect(result).toBe(meta)
|
|
340
|
+
})
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
describe('setSiteName', () => {
|
|
344
|
+
it('should set site name for Open Graph', () => {
|
|
345
|
+
meta.setSiteName('My Site')
|
|
346
|
+
expect(meta.getOg().getSiteName()).toBe('My Site')
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
it('should set site name for Twitter Card', () => {
|
|
350
|
+
meta.setSiteName('Twitter Site')
|
|
351
|
+
expect(meta.getTwitter().getSite()).toBe('Twitter Site')
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
it('should return this for chaining', () => {
|
|
355
|
+
const result = meta.setSiteName('Test')
|
|
356
|
+
expect(result).toBe(meta)
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
describe('setLocale', () => {
|
|
361
|
+
it('should set locale for Open Graph', () => {
|
|
362
|
+
meta.setLocale('ru_RU')
|
|
363
|
+
expect(meta.getOg().getLocale()).toBe('ru_RU')
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
it('should return this for chaining', () => {
|
|
367
|
+
const result = meta.setLocale('en_US')
|
|
368
|
+
expect(result).toBe(meta)
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
describe('setSuffix', () => {
|
|
373
|
+
it('should set suffix', () => {
|
|
374
|
+
meta.setSuffix('My Site')
|
|
375
|
+
meta.setTitle('Home')
|
|
376
|
+
|
|
377
|
+
expect(document.title).toBe('Home - My Site')
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
it('should allow removing suffix', () => {
|
|
381
|
+
meta.setSuffix('Site')
|
|
382
|
+
meta.setTitle('Page')
|
|
383
|
+
expect(document.title).toBe('Page - Site')
|
|
384
|
+
|
|
385
|
+
meta.setSuffix()
|
|
386
|
+
meta.setTitle('Another Page')
|
|
387
|
+
expect(document.title).toBe('Another Page')
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
it('should not add separator when suffix is empty', () => {
|
|
391
|
+
meta.setSuffix('')
|
|
392
|
+
meta.setTitle('Test')
|
|
393
|
+
|
|
394
|
+
expect(document.title).toBe('Test')
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
it('should apply suffix to OG and Twitter titles', () => {
|
|
398
|
+
meta.setSuffix('Site Name')
|
|
399
|
+
meta.setTitle('Page Title')
|
|
400
|
+
|
|
401
|
+
expect(meta.getOg().getTitle()).toBe('Page Title - Site Name')
|
|
402
|
+
expect(meta.getTwitter().getTitle()).toBe('Page Title - Site Name')
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
it('should update suffix dynamically', () => {
|
|
406
|
+
meta.setSuffix('First')
|
|
407
|
+
meta.setTitle('Title')
|
|
408
|
+
expect(document.title).toBe('Title - First')
|
|
409
|
+
|
|
410
|
+
meta.setSuffix('Second')
|
|
411
|
+
meta.setTitle('Title')
|
|
412
|
+
expect(document.title).toBe('Title - Second')
|
|
413
|
+
})
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
describe('html', () => {
|
|
417
|
+
it('should generate HTML for all meta tags', () => {
|
|
418
|
+
meta
|
|
419
|
+
.setTitle('Test Page')
|
|
420
|
+
.setDescription('Test description')
|
|
421
|
+
.setKeywords(['test', 'keywords'])
|
|
422
|
+
.setAuthor('John Doe')
|
|
423
|
+
|
|
424
|
+
const html = meta.html()
|
|
425
|
+
|
|
426
|
+
expect(html).toContain('name="description"')
|
|
427
|
+
expect(html).toContain('content="Test description"')
|
|
428
|
+
expect(html).toContain('name="keywords"')
|
|
429
|
+
expect(html).toContain('content="test, keywords"')
|
|
430
|
+
expect(html).toContain('name="author"')
|
|
431
|
+
expect(html).toContain('content="John Doe"')
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
it('should include Open Graph tags in HTML', () => {
|
|
435
|
+
meta.setImage('https://example.com/og.jpg')
|
|
436
|
+
meta.setSiteName('My Site')
|
|
437
|
+
|
|
438
|
+
const html = meta.html()
|
|
439
|
+
|
|
440
|
+
expect(html).toContain('property="og:image"')
|
|
441
|
+
expect(html).toContain('property="og:site_name"')
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
it('should include Twitter Card tags in HTML', () => {
|
|
445
|
+
meta.setImage('https://example.com/twitter.jpg')
|
|
446
|
+
|
|
447
|
+
const html = meta.html()
|
|
448
|
+
|
|
449
|
+
expect(html).toContain('name="twitter:image"')
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it('should escape special characters', () => {
|
|
453
|
+
meta.setDescription('Description with "quotes" & ampersands')
|
|
454
|
+
|
|
455
|
+
const html = meta.html()
|
|
456
|
+
|
|
457
|
+
expect(html).toContain('"')
|
|
458
|
+
expect(html).toContain('&')
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
it('should return combined HTML from all meta managers', () => {
|
|
462
|
+
meta
|
|
463
|
+
.setDescription('Standard meta')
|
|
464
|
+
.setImage('https://example.com/image.jpg')
|
|
465
|
+
.setCanonical('https://example.com/page')
|
|
466
|
+
|
|
467
|
+
const html = meta.html()
|
|
468
|
+
|
|
469
|
+
// Должен содержать теги из Meta, MetaOg и MetaTwitter
|
|
470
|
+
expect(html).toContain('name="description"')
|
|
471
|
+
expect(html).toContain('property="og:image"')
|
|
472
|
+
expect(html).toContain('name="twitter:image"')
|
|
473
|
+
expect(html).toContain('property="og:url"')
|
|
474
|
+
expect(html).toContain('name="twitter:url"')
|
|
475
|
+
})
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
describe('method chaining', () => {
|
|
479
|
+
it('should support chaining all setter methods', () => {
|
|
480
|
+
const result = meta
|
|
481
|
+
.setTitle('Chained Title')
|
|
482
|
+
.setDescription('Chained description')
|
|
483
|
+
.setKeywords(['chain', 'test'])
|
|
484
|
+
.setImage('https://example.com/chain.jpg')
|
|
485
|
+
.setCanonical('https://example.com/chain')
|
|
486
|
+
.setAuthor('Chain Author')
|
|
487
|
+
.setRobots(MetaRobots.indexFollow)
|
|
488
|
+
.setSiteName('Chain Site')
|
|
489
|
+
.setLocale('en_US')
|
|
490
|
+
|
|
491
|
+
expect(result).toBe(meta)
|
|
492
|
+
expect(meta.getTitle()).toBe('Chained Title')
|
|
493
|
+
expect(meta.getDescription()).toBe('Chained description')
|
|
494
|
+
expect(meta.getAuthor()).toBe('Chain Author')
|
|
495
|
+
})
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
describe('integration with MetaOg', () => {
|
|
499
|
+
it('should allow direct access to MetaOg methods', () => {
|
|
500
|
+
const og = meta.getOg()
|
|
501
|
+
|
|
502
|
+
og.setTitle('Direct OG Title')
|
|
503
|
+
expect(og.getTitle()).toBe('Direct OG Title')
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
it('should sync image between Meta and MetaOg', () => {
|
|
507
|
+
meta.setImage('https://example.com/sync.jpg')
|
|
508
|
+
|
|
509
|
+
expect(meta.getImage()).toBe('https://example.com/sync.jpg')
|
|
510
|
+
expect(meta.getOg().getImage()).toBe('https://example.com/sync.jpg')
|
|
511
|
+
})
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
describe('integration with MetaTwitter', () => {
|
|
515
|
+
it('should allow direct access to MetaTwitter methods', () => {
|
|
516
|
+
const twitter = meta.getTwitter()
|
|
517
|
+
|
|
518
|
+
twitter.setTitle('Direct Twitter Title')
|
|
519
|
+
expect(twitter.getTitle()).toBe('Direct Twitter Title')
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
it('should sync image between Meta and MetaTwitter', () => {
|
|
523
|
+
meta.setImage('https://example.com/twitter-sync.jpg')
|
|
524
|
+
|
|
525
|
+
expect(meta.getImage()).toBe('https://example.com/twitter-sync.jpg')
|
|
526
|
+
expect(meta.getTwitter().getImage()).toBe('https://example.com/twitter-sync.jpg')
|
|
527
|
+
})
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
describe('edge cases', () => {
|
|
531
|
+
it('should handle empty strings', () => {
|
|
532
|
+
meta.setTitle('')
|
|
533
|
+
meta.setDescription('')
|
|
534
|
+
meta.setKeywords('')
|
|
535
|
+
|
|
536
|
+
expect(meta.getTitle()).toBe('')
|
|
537
|
+
expect(meta.getDescription()).toBe('')
|
|
538
|
+
expect(meta.getKeywords()).toBe('')
|
|
539
|
+
})
|
|
540
|
+
|
|
541
|
+
it('should handle special characters in content', () => {
|
|
542
|
+
meta.setDescription('Test <script>alert("XSS")</script>')
|
|
543
|
+
|
|
544
|
+
const html = meta.html()
|
|
545
|
+
expect(html).toContain('<script>')
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
it('should handle very long strings', () => {
|
|
549
|
+
const longString = 'a'.repeat(1000)
|
|
550
|
+
meta.setDescription(longString)
|
|
551
|
+
|
|
552
|
+
expect(meta.getDescription()).toBe(longString)
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
it('should handle unicode characters', () => {
|
|
556
|
+
meta.setTitle('Заголовок на русском 🎉')
|
|
557
|
+
meta.setDescription('描述中文 日本語')
|
|
558
|
+
|
|
559
|
+
expect(meta.getTitle()).toBe('Заголовок на русском 🎉')
|
|
560
|
+
expect(meta.getDescription()).toBe('描述中文 日本語')
|
|
561
|
+
})
|
|
562
|
+
|
|
563
|
+
it('should handle keywords as empty array', () => {
|
|
564
|
+
meta.setKeywords([])
|
|
565
|
+
expect(meta.getKeywords()).toBe('')
|
|
566
|
+
})
|
|
567
|
+
})
|
|
568
|
+
|
|
569
|
+
describe('DOM synchronization', () => {
|
|
570
|
+
it('should update existing meta tags', () => {
|
|
571
|
+
// Создаем начальный тег
|
|
572
|
+
const initialMeta = document.createElement('meta')
|
|
573
|
+
initialMeta.setAttribute('name', 'description')
|
|
574
|
+
initialMeta.setAttribute('content', 'Initial content')
|
|
575
|
+
document.head.appendChild(initialMeta)
|
|
576
|
+
|
|
577
|
+
// Создаем новый экземпляр Meta
|
|
578
|
+
const newMeta = new Meta()
|
|
579
|
+
newMeta.setDescription('Updated content')
|
|
580
|
+
|
|
581
|
+
// Должен обновить существующий тег, а не создать новый
|
|
582
|
+
const metaTags = document.querySelectorAll('meta[name="description"]')
|
|
583
|
+
expect(metaTags.length).toBe(1)
|
|
584
|
+
expect(metaTags?.[0]?.getAttribute('content')).toBe('Updated content')
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
it('should read existing meta tags on initialization', () => {
|
|
588
|
+
// Устанавливаем теги в DOM
|
|
589
|
+
const descMeta = document.createElement('meta')
|
|
590
|
+
descMeta.setAttribute('name', 'description')
|
|
591
|
+
descMeta.setAttribute('content', 'Existing description')
|
|
592
|
+
document.head.appendChild(descMeta)
|
|
593
|
+
|
|
594
|
+
const keywordsMeta = document.createElement('meta')
|
|
595
|
+
keywordsMeta.setAttribute('name', 'keywords')
|
|
596
|
+
keywordsMeta.setAttribute('content', 'existing, keywords')
|
|
597
|
+
document.head.appendChild(keywordsMeta)
|
|
598
|
+
|
|
599
|
+
// Создаем новый экземпляр
|
|
600
|
+
const newMeta = new Meta()
|
|
601
|
+
|
|
602
|
+
// Должен прочитать существующие теги
|
|
603
|
+
expect(newMeta.getDescription()).toBe('Existing description')
|
|
604
|
+
expect(newMeta.getKeywords()).toBe('existing, keywords')
|
|
605
|
+
})
|
|
606
|
+
})
|
|
607
|
+
|
|
608
|
+
describe('SSR compatibility', () => {
|
|
609
|
+
it('should generate valid HTML for SSR', () => {
|
|
610
|
+
meta
|
|
611
|
+
.setTitle('SSR Page')
|
|
612
|
+
.setDescription('SSR Description')
|
|
613
|
+
.setKeywords(['ssr', 'test'])
|
|
614
|
+
.setCanonical('https://example.com/ssr')
|
|
615
|
+
.setImage('https://example.com/ssr.jpg')
|
|
616
|
+
|
|
617
|
+
const html = meta.html()
|
|
618
|
+
|
|
619
|
+
// HTML должен быть валидным
|
|
620
|
+
expect(html).toMatch(/<meta [^>]+>/g)
|
|
621
|
+
|
|
622
|
+
// Должен содержать все необходимые атрибуты
|
|
623
|
+
expect(html).toContain('name="description"')
|
|
624
|
+
expect(html).toContain('name="keywords"')
|
|
625
|
+
expect(html).toContain('property="og:image"')
|
|
626
|
+
expect(html).toContain('name="twitter:image"')
|
|
627
|
+
})
|
|
628
|
+
})
|
|
629
|
+
})
|