cloudinary-video-player 1.5.5 → 1.5.9
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/CHANGELOG.md +140 -21
- package/dist/cld-video-player.css +229 -2079
- package/dist/cld-video-player.js +200 -483
- package/dist/cld-video-player.light.css +231 -2081
- package/dist/cld-video-player.light.js +71 -23
- package/dist/cld-video-player.light.min.css +1 -1
- package/dist/cld-video-player.light.min.js +2 -23
- package/dist/cld-video-player.light.min.js.LICENSE.txt +23 -0
- package/dist/cld-video-player.min.css +1 -1
- package/dist/cld-video-player.min.js +2 -27
- package/dist/cld-video-player.min.js.LICENSE.txt +26 -0
- package/docs/interaction-area.html +104 -64
- package/package.json +23 -23
- package/src/assets/styles/components/interaction-areas.scss +165 -0
- package/src/assets/styles/components/themedButton.scss +48 -0
- package/src/assets/styles/icons.scss +149 -217
- package/src/assets/styles/main.scss +8 -30
- package/src/components/interaction-area/interaction-area.const.js +30 -0
- package/src/components/interaction-area/interaction-area.service.js +225 -0
- package/src/components/interaction-area/interaction-area.utils.js +236 -0
- package/src/components/logoButton/logo-button.js +3 -6
- package/src/components/themeButton/themedButton.const.js +3 -0
- package/src/components/themeButton/themedButton.js +25 -0
- package/src/config/defaults.js +3 -2
- package/src/extended-events.js +3 -0
- package/src/plugins/cloudinary/common.js +14 -6
- package/src/plugins/cloudinary/models/video-source/video-source.js +16 -12
- package/src/plugins/cloudinary/models/video-source/video-source.utils.js +28 -1
- package/src/plugins/colors/index.js +6 -1
- package/src/plugins/dash/videojs-dash.js +1 -1
- package/src/plugins/floating-player/index.js +3 -1
- package/src/utils/array.js +21 -0
- package/src/utils/dom.js +41 -2
- package/src/utils/object.js +26 -0
- package/src/utils/time.js +28 -1
- package/src/utils/type-inference.js +5 -1
- package/src/validators/validators-functions.js +48 -0
- package/src/validators/validators-types.js +78 -0
- package/src/validators/validators.js +110 -0
- package/src/video-player.const.js +23 -16
- package/src/video-player.js +47 -127
- package/src/video-player.utils.js +9 -70
- package/test/isValidConfig.test.js +224 -0
- package/test/unit/utils.test.js +27 -0
- package/test/unit/videoSource.test.js +155 -0
- package/types/video-player.d.ts +1 -1
package/src/video-player.js
CHANGED
|
@@ -10,23 +10,18 @@ import PlaylistWidget from './components/playlist/playlist-widget';
|
|
|
10
10
|
import qualitySelector from './components/qualitySelector/qualitySelector.js';
|
|
11
11
|
// #endif
|
|
12
12
|
import VideoSource from './plugins/cloudinary/models/video-source/video-source';
|
|
13
|
-
import {
|
|
14
|
-
import { isFunction, isString, noop, isPlainObject } from './utils/type-inference';
|
|
13
|
+
import { isFunction, isString, isPlainObject } from './utils/type-inference';
|
|
15
14
|
import {
|
|
16
|
-
addMetadataTrack,
|
|
17
15
|
extractOptions,
|
|
18
|
-
getMetaDataTracker,
|
|
19
16
|
getResolveVideoElement,
|
|
20
|
-
|
|
21
|
-
getZoomTransformation,
|
|
22
|
-
overrideDefaultVideojsComponents,
|
|
23
|
-
setInteractionAreasContainer
|
|
17
|
+
overrideDefaultVideojsComponents
|
|
24
18
|
} from './video-player.utils';
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from './
|
|
19
|
+
import { FLOATING_TO, FLUID_CLASS_NAME } from './video-player.const';
|
|
20
|
+
// #if (!process.env.WEBPACK_BUILD_LIGHT)
|
|
21
|
+
import { interactionAreaService } from './components/interaction-area/interaction-area.service';
|
|
22
|
+
// #endif
|
|
23
|
+
import { isValidConfig } from './validators/validators-functions';
|
|
24
|
+
import { playerValidators, sourceValidators } from './validators/validators';
|
|
30
25
|
|
|
31
26
|
|
|
32
27
|
// Register all plugins
|
|
@@ -73,11 +68,9 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
73
68
|
constructor(elem, initOptions, ready) {
|
|
74
69
|
super();
|
|
75
70
|
|
|
76
|
-
this._isZoomed = false;
|
|
77
|
-
this.unZoom = noop;
|
|
78
|
-
this._setStaticInteractionAreas = noop;
|
|
79
71
|
this._playlistWidget = null;
|
|
80
72
|
this.nbCalls = 0;
|
|
73
|
+
this._firstPlayed = false;
|
|
81
74
|
|
|
82
75
|
this.videoElement = getResolveVideoElement(elem);
|
|
83
76
|
|
|
@@ -101,6 +94,16 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
101
94
|
|
|
102
95
|
this.videojs = videojs(this.videoElement, this._videojsOptions);
|
|
103
96
|
|
|
97
|
+
// to do, should be change by isValidConfig
|
|
98
|
+
this._isPlayerConfigValid = true;
|
|
99
|
+
|
|
100
|
+
isValidConfig(this.options, playerValidators);
|
|
101
|
+
|
|
102
|
+
if (!this._isPlayerConfigValid) {
|
|
103
|
+
this.videojs.error('invalid player configuration');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
104
107
|
if (this._videojsOptions.muted) {
|
|
105
108
|
this.videojs.volume(0.4);
|
|
106
109
|
}
|
|
@@ -115,6 +118,10 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
115
118
|
imaAdsLoaded: (typeof google === 'object' && typeof google.ima === 'object')
|
|
116
119
|
};
|
|
117
120
|
|
|
121
|
+
// #if (!process.env.WEBPACK_BUILD_LIGHT)
|
|
122
|
+
this.interactionArea = interactionAreaService(this, this.playerOptions, this._videojsOptions);
|
|
123
|
+
// #endif
|
|
124
|
+
|
|
118
125
|
this._setCssClasses();
|
|
119
126
|
this._initPlugins(loaded);
|
|
120
127
|
this._initPlaylistWidget();
|
|
@@ -127,7 +134,7 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
127
134
|
this.videojs.on('error', () => {
|
|
128
135
|
const error = this.videojs.error();
|
|
129
136
|
if (error) {
|
|
130
|
-
const type = this.videojs.cloudinary.currentSourceType();
|
|
137
|
+
const type = this._isPlayerConfigValid && this.videojs.cloudinary.currentSourceType();
|
|
131
138
|
if (error.code === 4 && (type === 'VideoSource' || type === 'AudioSource')) {
|
|
132
139
|
this.videojs.error(null);
|
|
133
140
|
Utils.handleCldError(this, this.playerOptions);
|
|
@@ -152,13 +159,9 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
152
159
|
ready(this);
|
|
153
160
|
}
|
|
154
161
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.videojs.on('ended', () => {
|
|
160
|
-
this.unZoom();
|
|
161
|
-
});
|
|
162
|
+
// #if (!process.env.WEBPACK_BUILD_LIGHT)
|
|
163
|
+
this.interactionArea.init();
|
|
164
|
+
// #endif
|
|
162
165
|
});
|
|
163
166
|
|
|
164
167
|
if (this.adsEnabled && Object.keys(this.playerOptions.ads).length > 0 && typeof this.videojs.ima === 'object') {
|
|
@@ -191,22 +194,8 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
191
194
|
this._initSeekThumbs();
|
|
192
195
|
}
|
|
193
196
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this._currentTrack && this.videojs.removeRemoteTextTrack(this._currentTrack);
|
|
197
|
-
|
|
198
|
-
if (!interactionAreasConfig) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const vttUrl = interactionAreasConfig.vttUrl || TEMPLATE_INTERACTION_AREAS_VTT[interactionAreasConfig.template];
|
|
203
|
-
|
|
204
|
-
this.videojs.removeRemoteTextTrack(this._currentTrack);
|
|
205
|
-
|
|
206
|
-
if (!this._isZoomed && interactionAreasConfig.enable && vttUrl) {
|
|
207
|
-
this._currentTrack = addMetadataTrack(this.videojs, vttUrl);
|
|
208
|
-
this.addCueListener(interactionAreasConfig);
|
|
209
|
-
}
|
|
197
|
+
_isFullScreen() {
|
|
198
|
+
return this.videojs.player().isFullscreen();
|
|
210
199
|
}
|
|
211
200
|
|
|
212
201
|
_initIma (loaded) {
|
|
@@ -367,6 +356,11 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
367
356
|
_initAnalytics() {
|
|
368
357
|
const analyticsOpts = this.playerOptions.analytics;
|
|
369
358
|
|
|
359
|
+
if (!window.ga && analyticsOpts) {
|
|
360
|
+
console.error('Google Analytics script is missing');
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
|
|
370
364
|
if (analyticsOpts) {
|
|
371
365
|
const opts = typeof analyticsOpts === 'object' ? analyticsOpts : {};
|
|
372
366
|
this.videojs.analytics(opts);
|
|
@@ -377,7 +371,7 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
377
371
|
if (!this.isVideoReady()) {
|
|
378
372
|
if (this.nbCalls < maxNumberOfCalls) {
|
|
379
373
|
this.nbCalls++;
|
|
380
|
-
this.reTryId = this.videojs.setTimeout(this.reTryVideo, timeout);
|
|
374
|
+
this.reTryId = this.videojs.setTimeout(() => this.reTryVideo(maxNumberOfCalls, timeout), timeout);
|
|
381
375
|
} else {
|
|
382
376
|
let e = new Error('Video is not ready please try later');
|
|
383
377
|
this.videojs.trigger('error', e);
|
|
@@ -446,7 +440,7 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
446
440
|
}
|
|
447
441
|
|
|
448
442
|
_initFloatingPlayer() {
|
|
449
|
-
if (this.playerOptions.floatingWhenNotVisible) {
|
|
443
|
+
if (this.playerOptions.floatingWhenNotVisible !== FLOATING_TO.NONE) {
|
|
450
444
|
this.videojs.floatingPlayer({ 'floatTo': this.playerOptions.floatingWhenNotVisible });
|
|
451
445
|
}
|
|
452
446
|
}
|
|
@@ -509,91 +503,6 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
509
503
|
return this.options.playerOptions;
|
|
510
504
|
}
|
|
511
505
|
|
|
512
|
-
_setGoBackButton() {
|
|
513
|
-
const button = createElement('div', { 'class': 'go-back-button' });
|
|
514
|
-
|
|
515
|
-
button.addEventListener('click', () => {
|
|
516
|
-
this.unZoom();
|
|
517
|
-
}, false);
|
|
518
|
-
|
|
519
|
-
const tracksContainer = createElement('div', { 'class': INTERACTION_AREAS_CONTAINER_CLASS_NAME }, button);
|
|
520
|
-
setInteractionAreasContainer(this.videojs, tracksContainer);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
addInteractionAreas(interactionAreas, interactionAreasOptions) {
|
|
524
|
-
this._setStaticInteractionAreas = () => {
|
|
525
|
-
this._addInteractionAreasItems(interactionAreas, interactionAreasOptions);
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
this._addInteractionAreasItems(interactionAreas, interactionAreasOptions);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
getInteractionAreasConfig() {
|
|
532
|
-
return this.videojs.currentSource().cldSrc.getInteractionAreas();
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
_onZoom(src, newOption, item) {
|
|
536
|
-
const currentSource = this.videojs.currentSource();
|
|
537
|
-
const { cldSrc } = currentSource;
|
|
538
|
-
const currentSrcOptions = cldSrc.getInitOptions();
|
|
539
|
-
const option = newOption || { transformation: currentSrcOptions.transformation.toOptions() };
|
|
540
|
-
const transformation = !src && getZoomTransformation(this.videoElement, item);
|
|
541
|
-
const sourceOptions = transformation ? videojs.mergeOptions({ transformation }, option) : option;
|
|
542
|
-
|
|
543
|
-
const newSource = cldSrc.isRawUrl ? currentSource.src : { publicId: cldSrc.publicId() };
|
|
544
|
-
this.source(transformation ? { publicId: cldSrc.publicId() } : src, sourceOptions).play();
|
|
545
|
-
|
|
546
|
-
this._isZoomed = true;
|
|
547
|
-
|
|
548
|
-
this._setGoBackButton();
|
|
549
|
-
|
|
550
|
-
this.unZoom = () => {
|
|
551
|
-
if (this._isZoomed) {
|
|
552
|
-
this._isZoomed = false;
|
|
553
|
-
this._setStaticInteractionAreas();
|
|
554
|
-
this.source(newSource, currentSrcOptions).play();
|
|
555
|
-
}
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
_addInteractionAreasItems(interactionAreasData, interactionAreasOptions = {}) {
|
|
560
|
-
const interactionAreasItems = interactionAreasData.map((item, index) => {
|
|
561
|
-
return getInteractionAreaItem(item, (event) => {
|
|
562
|
-
interactionAreasOptions.onClick && interactionAreasOptions.onClick({
|
|
563
|
-
item,
|
|
564
|
-
index,
|
|
565
|
-
event,
|
|
566
|
-
zoom: (source, option) => {
|
|
567
|
-
this._onZoom(source, option, item);
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
|
-
});
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
const interactionAreasContainer = createElement('div', { 'class': INTERACTION_AREAS_CONTAINER_CLASS_NAME }, interactionAreasItems);
|
|
574
|
-
setInteractionAreasContainer(this.videojs, interactionAreasContainer);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
addCueListener(interactionAreasConfig) {
|
|
578
|
-
const textTracks = this.videojs.textTracks();
|
|
579
|
-
if (!textTracks.length) {
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
const track = getMetaDataTracker(textTracks);
|
|
584
|
-
|
|
585
|
-
if (!track) {
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
track.mode = 'hidden';
|
|
590
|
-
|
|
591
|
-
track.addEventListener('cuechange', () => {
|
|
592
|
-
const tracksData = JSON.parse(track.activeCues[0].text);
|
|
593
|
-
this._addInteractionAreasItems(tracksData, interactionAreasConfig);
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
|
|
597
506
|
currentPublicId() {
|
|
598
507
|
return this.videojs.cloudinary.currentPublicId();
|
|
599
508
|
}
|
|
@@ -607,6 +516,17 @@ class VideoPlayer extends Utils.mixin(Eventable) {
|
|
|
607
516
|
}
|
|
608
517
|
|
|
609
518
|
source(publicId, options = {}) {
|
|
519
|
+
if (!this._isPlayerConfigValid) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const isSourceConfigValid = isValidConfig(options, sourceValidators);
|
|
524
|
+
|
|
525
|
+
if (!isSourceConfigValid) {
|
|
526
|
+
this.videojs.error('invalid source configuration');
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
610
530
|
if (publicId instanceof VideoSource) {
|
|
611
531
|
return this.videojs.cloudinary.source(publicId, options);
|
|
612
532
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createElement } from './utils/dom';
|
|
2
1
|
import videojs from 'video.js';
|
|
3
2
|
import Utils from './utils';
|
|
4
3
|
import defaults from './config/defaults';
|
|
@@ -6,74 +5,11 @@ import {
|
|
|
6
5
|
CLOUDINARY_PARAMS,
|
|
7
6
|
DEFAULT_HLS_OPTIONS,
|
|
8
7
|
PLAYER_PARAMS,
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
FLUID_CLASS_NAME,
|
|
9
|
+
AUTO_PLAY_MODE
|
|
11
10
|
} from './video-player.const';
|
|
12
11
|
import { isString } from './utils/type-inference';
|
|
13
12
|
|
|
14
|
-
export const getMetaDataTracker = (textTracks) => {
|
|
15
|
-
for (let i = 0; textTracks.length; i++) {
|
|
16
|
-
const value = textTracks[i];
|
|
17
|
-
if (value.kind === 'metadata') {
|
|
18
|
-
return value;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export const setInteractionAreasContainer = (videojs, newInteractionAreasContainer) => {
|
|
25
|
-
const videoContainer = videojs.el();
|
|
26
|
-
const currentInteractionAreasContainer = videoContainer.querySelector(`.${INTERACTION_AREAS_CONTAINER_CLASS_NAME}`);
|
|
27
|
-
|
|
28
|
-
if (currentInteractionAreasContainer) {
|
|
29
|
-
currentInteractionAreasContainer.replaceWith(newInteractionAreasContainer);
|
|
30
|
-
} else {
|
|
31
|
-
videoContainer.append(newInteractionAreasContainer);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const percentageToFixedValue = (outOf, value) => (outOf / (100 / +value));
|
|
36
|
-
|
|
37
|
-
export const getZoomTransformation = (videoElement, interactionAreaItem) => {
|
|
38
|
-
|
|
39
|
-
const { videoHeight, videoWidth } = videoElement;
|
|
40
|
-
|
|
41
|
-
const itemX = percentageToFixedValue(videoWidth, interactionAreaItem.left);
|
|
42
|
-
const itemY = percentageToFixedValue(videoHeight, interactionAreaItem.top);
|
|
43
|
-
const itemWidth = percentageToFixedValue(videoWidth, interactionAreaItem.width);
|
|
44
|
-
const itemHeight = percentageToFixedValue(videoHeight, interactionAreaItem.height);
|
|
45
|
-
|
|
46
|
-
const videoAspectRatio = videoWidth / videoHeight;
|
|
47
|
-
const itemAspectRatio = itemWidth / itemHeight;
|
|
48
|
-
|
|
49
|
-
const width = Math.round(itemAspectRatio > 1 || videoAspectRatio > 1 ? itemHeight * itemAspectRatio : itemWidth);
|
|
50
|
-
const height = Math.round(width / videoAspectRatio);
|
|
51
|
-
|
|
52
|
-
const x = Math.round(itemX - (width - itemWidth) / 2);
|
|
53
|
-
const y = Math.round(itemY - (height - itemHeight) / 2);
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
width,
|
|
57
|
-
height,
|
|
58
|
-
x: Math.min(Math.max(x, 0), videoWidth - width),
|
|
59
|
-
y: Math.min(Math.max(y, 0), videoHeight - height),
|
|
60
|
-
crop: 'crop'
|
|
61
|
-
};
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export const getInteractionAreaItem = (item, onClick) => {
|
|
65
|
-
const element = createElement('div', { class: 'video-player-interaction-area' });
|
|
66
|
-
element.style.left = `${item.left}%`;
|
|
67
|
-
element.style.top = `${item.top}%`;
|
|
68
|
-
element.style.width = `${item.width}%`;
|
|
69
|
-
element.style.height = `${item.height}%`;
|
|
70
|
-
|
|
71
|
-
element.addEventListener('click', onClick, false);
|
|
72
|
-
|
|
73
|
-
return element;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
|
|
77
13
|
export const addMetadataTrack = (videoJs, vttSource) => {
|
|
78
14
|
return videoJs.addRemoteTextTrack({
|
|
79
15
|
kind: 'metadata',
|
|
@@ -83,6 +19,10 @@ export const addMetadataTrack = (videoJs, vttSource) => {
|
|
|
83
19
|
}, true).track;
|
|
84
20
|
};
|
|
85
21
|
|
|
22
|
+
export const isLight = (opts) => {
|
|
23
|
+
return opts.class.indexOf('cld-video-player-skin-light') > -1 || opts.skin === 'light';
|
|
24
|
+
};
|
|
25
|
+
|
|
86
26
|
export const getResolveVideoElement = (elem) => {
|
|
87
27
|
if (isString(elem)) {
|
|
88
28
|
let id = elem;
|
|
@@ -117,11 +57,11 @@ export const normalizeAutoplay = (options) => {
|
|
|
117
57
|
const autoplayMode = options.autoplayMode;
|
|
118
58
|
if (autoplayMode) {
|
|
119
59
|
switch (autoplayMode) {
|
|
120
|
-
case
|
|
60
|
+
case AUTO_PLAY_MODE.ALWAYS:
|
|
121
61
|
options.autoplay = true;
|
|
122
62
|
break;
|
|
123
|
-
case
|
|
124
|
-
case
|
|
63
|
+
case AUTO_PLAY_MODE.ON_SCROLL:
|
|
64
|
+
case AUTO_PLAY_MODE.NEVER:
|
|
125
65
|
default:
|
|
126
66
|
options.autoplay = false;
|
|
127
67
|
}
|
|
@@ -134,7 +74,6 @@ export const extractOptions = (elem, options) => {
|
|
|
134
74
|
if (videojs.dom.hasClass(elem, FLUID_CLASS_NAME) || videojs.dom.hasClass(elem, 'vjs-fluid')) {
|
|
135
75
|
options.fluid = true;
|
|
136
76
|
}
|
|
137
|
-
|
|
138
77
|
// Default HLS options < Default options < Markup options < Player options
|
|
139
78
|
options = Utils.assign({}, DEFAULT_HLS_OPTIONS, defaults, elemOptions, options);
|
|
140
79
|
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { isValidConfig } from '../src/validators/validators-functions';
|
|
2
|
+
import { validator } from '../src/validators/validators-types';
|
|
3
|
+
import { noop } from '../src/utils/type-inference';
|
|
4
|
+
|
|
5
|
+
describe('test isValidConfig method', () => {
|
|
6
|
+
|
|
7
|
+
describe('should be a number', () => {
|
|
8
|
+
|
|
9
|
+
const validators = {
|
|
10
|
+
test: validator.isNumber
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
it('is valid number', () => {
|
|
14
|
+
const isValid = isValidConfig({
|
|
15
|
+
test: 1
|
|
16
|
+
}, validators);
|
|
17
|
+
|
|
18
|
+
expect(isValid).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('is invalid number', () => {
|
|
22
|
+
const isValid = isValidConfig({
|
|
23
|
+
test: 'a'
|
|
24
|
+
}, validators);
|
|
25
|
+
|
|
26
|
+
expect(isValid).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('should be a string', () => {
|
|
31
|
+
|
|
32
|
+
const validators = {
|
|
33
|
+
test: validator.isString
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
it('is valid string', () => {
|
|
37
|
+
const isValid = isValidConfig({
|
|
38
|
+
test: 'a'
|
|
39
|
+
}, validators);
|
|
40
|
+
|
|
41
|
+
expect(isValid).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('is invalid string', () => {
|
|
45
|
+
const isValid = isValidConfig({
|
|
46
|
+
test: 1
|
|
47
|
+
}, validators);
|
|
48
|
+
|
|
49
|
+
expect(isValid).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('should be a boolean', () => {
|
|
54
|
+
|
|
55
|
+
const validators = {
|
|
56
|
+
test: validator.isBoolean
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
it('is valid boolean', () => {
|
|
60
|
+
const isValid = isValidConfig({
|
|
61
|
+
test: true
|
|
62
|
+
}, validators);
|
|
63
|
+
|
|
64
|
+
expect(isValid).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('is invalid boolean', () => {
|
|
68
|
+
const isValid = isValidConfig({
|
|
69
|
+
test: 1
|
|
70
|
+
}, validators);
|
|
71
|
+
|
|
72
|
+
expect(isValid).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('should be a function', () => {
|
|
77
|
+
|
|
78
|
+
const validators = {
|
|
79
|
+
test: validator.isFunction
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
it('is valid function', () => {
|
|
83
|
+
const isValid = isValidConfig({
|
|
84
|
+
test: noop
|
|
85
|
+
}, validators);
|
|
86
|
+
|
|
87
|
+
expect(isValid).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('is invalid function', () => {
|
|
91
|
+
const isValid = isValidConfig({
|
|
92
|
+
test: 1
|
|
93
|
+
}, validators);
|
|
94
|
+
|
|
95
|
+
expect(isValid).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('should be an array Of strings', () => {
|
|
100
|
+
|
|
101
|
+
const validators = {
|
|
102
|
+
test: validator.isArrayOfStrings
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
it('is valid array of strings', () => {
|
|
106
|
+
const isValid = isValidConfig({
|
|
107
|
+
test: ['a', 'b', 'c']
|
|
108
|
+
}, validators);
|
|
109
|
+
|
|
110
|
+
expect(isValid).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('is invalid array of strings', () => {
|
|
114
|
+
const isValid = isValidConfig({
|
|
115
|
+
test: 1
|
|
116
|
+
}, validators);
|
|
117
|
+
|
|
118
|
+
expect(isValid).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('should be an array Of numbers', () => {
|
|
123
|
+
|
|
124
|
+
const validators = {
|
|
125
|
+
test: validator.isArrayOfNumbers
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
it('is valid array of numbers', () => {
|
|
129
|
+
const isValid = isValidConfig({
|
|
130
|
+
test: [1, 1, 1]
|
|
131
|
+
}, validators);
|
|
132
|
+
|
|
133
|
+
expect(isValid).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('is invalid array of numbers', () => {
|
|
137
|
+
const isValid = isValidConfig({
|
|
138
|
+
test: 1
|
|
139
|
+
}, validators);
|
|
140
|
+
|
|
141
|
+
expect(isValid).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('should be an object', () => {
|
|
146
|
+
const validators = {
|
|
147
|
+
test: validator.isPlainObject
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
it('is valid object', () => {
|
|
151
|
+
const isValid = isValidConfig({
|
|
152
|
+
test: { a: 1 }
|
|
153
|
+
}, validators);
|
|
154
|
+
|
|
155
|
+
expect(isValid).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('is invalid object', () => {
|
|
159
|
+
const isValid = isValidConfig({
|
|
160
|
+
test: 1
|
|
161
|
+
}, validators);
|
|
162
|
+
|
|
163
|
+
expect(isValid).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('should be an array of object', () => {
|
|
168
|
+
const validators = {
|
|
169
|
+
test: validator.isArrayOfObjects({
|
|
170
|
+
a: validator.isString,
|
|
171
|
+
b: validator.isNumber,
|
|
172
|
+
c: validator.isBoolean
|
|
173
|
+
})
|
|
174
|
+
};
|
|
175
|
+
it('is valid array of object', () => {
|
|
176
|
+
const isValid = isValidConfig({
|
|
177
|
+
test: [{ a: 'a', b: 1, c: true }]
|
|
178
|
+
}, validators);
|
|
179
|
+
|
|
180
|
+
expect(isValid).toBe(true);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('is invalid object', () => {
|
|
184
|
+
const isValid = isValidConfig({
|
|
185
|
+
test: [{ a: 'a', b: 1, c: 1 }]
|
|
186
|
+
}, validators);
|
|
187
|
+
|
|
188
|
+
expect(isValid).toBe(false);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
describe('or validator', () => {
|
|
194
|
+
const validators = {
|
|
195
|
+
test: validator.or(validator.isNumber, validator.isString)
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
it('could be a number', () => {
|
|
199
|
+
const isValid = isValidConfig({
|
|
200
|
+
test: 1
|
|
201
|
+
}, validators);
|
|
202
|
+
|
|
203
|
+
expect(isValid).toBe(true);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('could be a string', () => {
|
|
207
|
+
const isValid = isValidConfig({
|
|
208
|
+
test: 'a'
|
|
209
|
+
}, validators);
|
|
210
|
+
|
|
211
|
+
expect(isValid).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('is invalid or', () => {
|
|
215
|
+
const isValid = isValidConfig({
|
|
216
|
+
test: true
|
|
217
|
+
}, validators);
|
|
218
|
+
|
|
219
|
+
expect(isValid).toBe(false);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { get } from '../../src/utils/object.js';
|
|
2
|
+
|
|
3
|
+
describe('test get utils function', () => {
|
|
4
|
+
const value = { a: { b: [{ c: 2 }], d: undefined } };
|
|
5
|
+
|
|
6
|
+
it('should get primitive value', () => {
|
|
7
|
+
expect(get(value, 'a.b.0.c')).toBe(value.a.b[0].c);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should get object value', () => {
|
|
11
|
+
expect(get(value, 'a.b')).toBe(value.a.b);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should get default value', () => {
|
|
15
|
+
const defaultValue = 10;
|
|
16
|
+
expect(get(value, 'a.c', defaultValue)).toBe(defaultValue);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should get default value if value is undefined', () => {
|
|
20
|
+
expect(get(value, 'a.d', 10)).toBe(10);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should get default value if the value is not an object', () => {
|
|
24
|
+
expect(get(1, 'a.b', 12)).toBe(12);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
});
|