How to use userConfig method in Best

Best JavaScript code snippet using best

resolveConfig.test.js

Source:resolveConfig.test.js Github

copy

Full Screen

1import resolveConfig from '../src/util/resolveConfig'2import corePluginList from '../src/corePluginList'3test('prefix key overrides default prefix', () => {4 const userConfig = {5 prefix: 'tw-',6 }7 const defaultConfig = {8 prefix: '',9 important: false,10 separator: ':',11 content: [],12 theme: {13 screens: {14 mobile: '400px',15 },16 },17 }18 const result = resolveConfig([userConfig, defaultConfig])19 expect(result).toMatchObject({20 prefix: 'tw-',21 important: false,22 separator: ':',23 theme: {24 screens: {25 mobile: '400px',26 },27 },28 })29})30test('important key overrides default important', () => {31 const userConfig = {32 important: true,33 }34 const defaultConfig = {35 prefix: '',36 important: false,37 separator: ':',38 content: [],39 theme: {40 screens: {41 mobile: '400px',42 },43 },44 }45 const result = resolveConfig([userConfig, defaultConfig])46 expect(result).toMatchObject({47 prefix: '',48 important: true,49 separator: ':',50 theme: {51 screens: {52 mobile: '400px',53 },54 },55 })56})57test('important (selector) key overrides default important', () => {58 const userConfig = {59 important: '#app',60 }61 const defaultConfig = {62 prefix: '',63 important: false,64 separator: ':',65 content: [],66 theme: {67 screens: {68 mobile: '400px',69 },70 },71 }72 const result = resolveConfig([userConfig, defaultConfig])73 expect(result).toMatchObject({74 prefix: '',75 important: '#app',76 separator: ':',77 theme: {78 screens: {79 mobile: '400px',80 },81 },82 })83})84test('separator key overrides default separator', () => {85 const userConfig = {86 separator: '__',87 }88 const defaultConfig = {89 prefix: '',90 important: false,91 separator: ':',92 content: [],93 theme: {94 screens: {95 mobile: '400px',96 },97 },98 }99 const result = resolveConfig([userConfig, defaultConfig])100 expect(result).toMatchObject({101 prefix: '',102 important: false,103 separator: '__',104 theme: {105 screens: {106 mobile: '400px',107 },108 },109 })110})111test('theme key is merged instead of replaced', () => {112 const userConfig = {113 theme: {114 screens: {115 mobile: '400px',116 },117 },118 }119 const defaultConfig = {120 prefix: '-',121 important: false,122 separator: ':',123 content: [],124 theme: {125 colors: {126 'grey-darker': '#606f7b',127 'grey-dark': '#8795a1',128 grey: '#b8c2cc',129 'grey-light': '#dae1e7',130 'grey-lighter': '#f1f5f8',131 },132 fonts: {133 sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],134 serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],135 },136 screens: {137 sm: '500px',138 md: '750px',139 lg: '1000px',140 },141 },142 }143 const result = resolveConfig([userConfig, defaultConfig])144 expect(result).toMatchObject({145 prefix: '-',146 important: false,147 separator: ':',148 theme: {149 colors: {150 'grey-darker': '#606f7b',151 'grey-dark': '#8795a1',152 grey: '#b8c2cc',153 'grey-light': '#dae1e7',154 'grey-lighter': '#f1f5f8',155 },156 fonts: {157 sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'],158 serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'],159 },160 screens: {161 mobile: '400px',162 },163 },164 })165})166test('theme key is deeply merged instead of replaced', () => {167 const userConfig = {168 theme: {169 extend: {170 colors: {171 grey: {172 darker: '#606f7b',173 dark: '#8795a1',174 },175 },176 },177 },178 }179 const defaultConfig = {180 prefix: '-',181 important: false,182 separator: ':',183 content: [],184 theme: {185 colors: {186 grey: {187 grey: '#b8c2cc',188 light: '#dae1e7',189 lighter: '#f1f5f8',190 },191 },192 },193 }194 const result = resolveConfig([userConfig, defaultConfig])195 expect(result).toMatchObject({196 prefix: '-',197 important: false,198 separator: ':',199 theme: {200 colors: {201 grey: {202 darker: '#606f7b',203 dark: '#8795a1',204 grey: '#b8c2cc',205 light: '#dae1e7',206 lighter: '#f1f5f8',207 },208 },209 },210 })211})212test('missing top level keys are pulled from the default config', () => {213 const userConfig = {}214 const defaultConfig = {215 prefix: '-',216 important: false,217 separator: ':',218 content: [],219 theme: {220 colors: { green: '#00ff00' },221 screens: {222 mobile: '400px',223 },224 },225 }226 const result = resolveConfig([userConfig, defaultConfig])227 expect(result).toMatchObject({228 prefix: '-',229 important: false,230 separator: ':',231 theme: {232 colors: { green: '#00ff00' },233 screens: {234 mobile: '400px',235 },236 },237 })238})239test('functions in the default theme section are lazily evaluated', () => {240 const userConfig = {241 theme: {242 colors: {243 red: 'red',244 green: 'green',245 blue: 'blue',246 },247 },248 }249 const defaultConfig = {250 prefix: '-',251 important: false,252 separator: ':',253 content: [],254 theme: {255 colors: {256 cyan: 'cyan',257 magenta: 'magenta',258 yellow: 'yellow',259 },260 backgroundColors: (theme) => theme('colors'),261 textColors: (theme) => theme('colors'),262 },263 }264 const result = resolveConfig([userConfig, defaultConfig])265 expect(result).toMatchObject({266 prefix: '-',267 important: false,268 separator: ':',269 theme: {270 colors: {271 red: 'red',272 green: 'green',273 blue: 'blue',274 },275 backgroundColors: {276 red: 'red',277 green: 'green',278 blue: 'blue',279 },280 textColors: {281 red: 'red',282 green: 'green',283 blue: 'blue',284 },285 },286 })287})288test('functions in the user theme section are lazily evaluated', () => {289 const userConfig = {290 theme: {291 colors: {292 red: 'red',293 green: 'green',294 blue: 'blue',295 },296 backgroundColors: (theme) => ({297 ...theme('colors'),298 customBackground: '#bada55',299 }),300 textColors: (theme) => ({301 ...theme('colors'),302 customText: '#facade',303 }),304 },305 }306 const defaultConfig = {307 prefix: '-',308 important: false,309 separator: ':',310 content: [],311 theme: {312 colors: {313 cyan: 'cyan',314 magenta: 'magenta',315 yellow: 'yellow',316 },317 backgroundColors: ({ colors }) => colors,318 textColors: ({ colors }) => colors,319 },320 }321 const result = resolveConfig([userConfig, defaultConfig])322 expect(result).toMatchObject({323 prefix: '-',324 important: false,325 separator: ':',326 theme: {327 colors: {328 red: 'red',329 green: 'green',330 blue: 'blue',331 },332 backgroundColors: {333 red: 'red',334 green: 'green',335 blue: 'blue',336 customBackground: '#bada55',337 },338 textColors: {339 red: 'red',340 green: 'green',341 blue: 'blue',342 customText: '#facade',343 },344 },345 })346})347test('theme values in the extend section extend the existing theme', () => {348 const userConfig = {349 theme: {350 extend: {351 opacity: {352 25: '25',353 75: '.75',354 },355 backgroundColors: {356 customBackground: '#bada55',357 },358 },359 },360 }361 const defaultConfig = {362 prefix: '-',363 important: false,364 separator: ':',365 content: [],366 theme: {367 colors: {368 cyan: 'cyan',369 magenta: 'magenta',370 yellow: 'yellow',371 },372 opacity: {373 0: '0',374 50: '.5',375 100: '1',376 },377 backgroundColors: (theme) => theme('colors'),378 },379 }380 const result = resolveConfig([userConfig, defaultConfig])381 expect(result).toMatchObject({382 prefix: '-',383 important: false,384 separator: ':',385 theme: {386 colors: {387 cyan: 'cyan',388 magenta: 'magenta',389 yellow: 'yellow',390 },391 opacity: {392 0: '0',393 50: '.5',394 100: '1',395 25: '25',396 75: '.75',397 },398 backgroundColors: {399 cyan: 'cyan',400 magenta: 'magenta',401 yellow: 'yellow',402 customBackground: '#bada55',403 },404 },405 })406})407test('theme values in the extend section extend the user theme', () => {408 const userConfig = {409 theme: {410 opacity: {411 0: '0',412 20: '.2',413 40: '.4',414 },415 height: (theme) => theme('width'),416 extend: {417 opacity: {418 60: '.6',419 80: '.8',420 100: '1',421 },422 height: {423 customHeight: '500vh',424 },425 },426 },427 }428 const defaultConfig = {429 prefix: '-',430 important: false,431 separator: ':',432 content: [],433 theme: {434 opacity: {435 0: '0',436 50: '.5',437 100: '1',438 },439 height: {440 0: 0,441 full: '100%',442 },443 width: {444 0: 0,445 1: '.25rem',446 2: '.5rem',447 3: '.75rem',448 4: '1rem',449 },450 },451 }452 const result = resolveConfig([userConfig, defaultConfig])453 expect(result).toMatchObject({454 prefix: '-',455 important: false,456 separator: ':',457 theme: {458 opacity: {459 0: '0',460 20: '.2',461 40: '.4',462 60: '.6',463 80: '.8',464 100: '1',465 },466 height: {467 0: 0,468 1: '.25rem',469 2: '.5rem',470 3: '.75rem',471 4: '1rem',472 customHeight: '500vh',473 },474 width: {475 0: 0,476 1: '.25rem',477 2: '.5rem',478 3: '.75rem',479 4: '1rem',480 },481 },482 })483})484test('theme values in the extend section can extend values that are depended on lazily', () => {485 const userConfig = {486 theme: {487 extend: {488 colors: {489 red: 'red',490 green: 'green',491 blue: 'blue',492 },493 backgroundColors: {494 customBackground: '#bada55',495 },496 },497 },498 }499 const defaultConfig = {500 prefix: '-',501 important: false,502 separator: ':',503 content: [],504 theme: {505 colors: {506 cyan: 'cyan',507 magenta: 'magenta',508 yellow: 'yellow',509 },510 backgroundColors: (theme) => theme('colors'),511 },512 }513 const result = resolveConfig([userConfig, defaultConfig])514 expect(result).toMatchObject({515 prefix: '-',516 important: false,517 separator: ':',518 theme: {519 colors: {520 cyan: 'cyan',521 magenta: 'magenta',522 yellow: 'yellow',523 red: 'red',524 green: 'green',525 blue: 'blue',526 },527 backgroundColors: {528 cyan: 'cyan',529 magenta: 'magenta',530 yellow: 'yellow',531 red: 'red',532 green: 'green',533 blue: 'blue',534 customBackground: '#bada55',535 },536 },537 })538})539test('theme values in the extend section are not deeply merged when they are simple arrays', () => {540 const userConfig = {541 theme: {542 extend: {543 fonts: {544 sans: ['Comic Sans'],545 },546 },547 },548 }549 const defaultConfig = {550 prefix: '-',551 important: false,552 separator: ':',553 content: [],554 theme: {555 fonts: {556 sans: ['system-ui', 'Helvetica Neue', 'sans-serif'],557 serif: ['Constantia', 'Georgia', 'serif'],558 mono: ['Menlo', 'Courier New', 'monospace'],559 },560 },561 }562 const result = resolveConfig([userConfig, defaultConfig])563 expect(result).toMatchObject({564 prefix: '-',565 important: false,566 separator: ':',567 theme: {568 fonts: {569 sans: ['Comic Sans'],570 serif: ['Constantia', 'Georgia', 'serif'],571 mono: ['Menlo', 'Courier New', 'monospace'],572 },573 },574 })575})576test('theme values in the extend section are deeply merged, when they are arrays of objects', () => {577 const userConfig = {578 theme: {579 extend: {580 typography: {581 ArrayArray: {582 css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }],583 },584 ObjectArray: {585 css: { a: { backgroundColor: 'red' } },586 },587 ArrayObject: {588 css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }],589 },590 },591 },592 },593 }594 const defaultConfig = {595 prefix: '-',596 important: false,597 separator: ':',598 content: [],599 theme: {600 typography: {601 ArrayArray: {602 css: [{ a: { underline: 'none' } }],603 },604 ObjectArray: {605 css: [{ a: { underline: 'none' } }],606 },607 ArrayObject: {608 css: { a: { underline: 'none' } },609 },610 },611 },612 }613 const result = resolveConfig([userConfig, defaultConfig])614 expect(result).toMatchObject({615 prefix: '-',616 important: false,617 separator: ':',618 theme: {619 typography: {620 ArrayArray: {621 css: [622 { a: { underline: 'none' } },623 { a: { backgroundColor: 'red' } },624 { a: { color: 'green' } },625 ],626 },627 ObjectArray: {628 css: [{ a: { underline: 'none' } }, { a: { backgroundColor: 'red' } }],629 },630 ArrayObject: {631 css: [632 { a: { underline: 'none' } },633 { a: { backgroundColor: 'red' } },634 { a: { color: 'green' } },635 ],636 },637 },638 },639 })640})641test('the theme function can use a default value if the key is missing', () => {642 const userConfig = {643 theme: {644 colors: {645 red: 'red',646 green: 'green',647 blue: 'blue',648 },649 },650 }651 const defaultConfig = {652 prefix: '-',653 important: false,654 separator: ':',655 content: [],656 theme: {657 colors: {658 cyan: 'cyan',659 magenta: 'magenta',660 yellow: 'yellow',661 },662 borderColor: (theme) => ({663 default: theme('colors.gray', 'currentColor'),664 ...theme('colors'),665 }),666 },667 }668 const result = resolveConfig([userConfig, defaultConfig])669 expect(result).toMatchObject({670 prefix: '-',671 important: false,672 separator: ':',673 theme: {674 colors: {675 red: 'red',676 green: 'green',677 blue: 'blue',678 },679 borderColor: {680 default: 'currentColor',681 red: 'red',682 green: 'green',683 blue: 'blue',684 },685 },686 })687})688test('the theme function can resolve function values', () => {689 const userConfig = {690 theme: {691 textColor: (theme) => ({692 lime: 'lime',693 ...theme('colors'),694 }),695 backgroundColor: (theme) => ({696 orange: 'orange',697 ...theme('textColor'),698 }),699 borderColor: (theme) => theme('backgroundColor'),700 },701 }702 const defaultConfig = {703 prefix: '-',704 important: false,705 separator: ':',706 content: [],707 theme: {708 colors: {709 red: 'red',710 green: 'green',711 blue: 'blue',712 },713 },714 }715 const result = resolveConfig([userConfig, defaultConfig])716 expect(result).toMatchObject({717 prefix: '-',718 important: false,719 separator: ':',720 theme: {721 colors: {722 red: 'red',723 green: 'green',724 blue: 'blue',725 },726 textColor: {727 lime: 'lime',728 red: 'red',729 green: 'green',730 blue: 'blue',731 },732 backgroundColor: {733 lime: 'lime',734 orange: 'orange',735 red: 'red',736 green: 'green',737 blue: 'blue',738 },739 borderColor: {740 lime: 'lime',741 orange: 'orange',742 red: 'red',743 green: 'green',744 blue: 'blue',745 },746 },747 })748})749test('the theme function can resolve deep function values', () => {750 const userConfig = {751 theme: {752 minWidth: (theme) => ({753 '1/3': theme('width.1/3'),754 }),755 },756 }757 const defaultConfig = {758 prefix: '-',759 important: false,760 separator: ':',761 content: [],762 theme: {763 spacing: {764 0: '0',765 },766 width: (theme) => ({767 ...theme('spacing'),768 '1/3': '33.33333%',769 }),770 },771 }772 const result = resolveConfig([userConfig, defaultConfig])773 expect(result).toMatchObject({774 prefix: '-',775 important: false,776 separator: ':',777 theme: {778 spacing: {779 0: '0',780 },781 width: {782 0: '0',783 '1/3': '33.33333%',784 },785 minWidth: {786 '1/3': '33.33333%',787 },788 },789 })790})791test('theme values in the extend section are lazily evaluated', () => {792 const userConfig = {793 theme: {794 colors: {795 red: 'red',796 green: 'green',797 blue: 'blue',798 },799 extend: {800 colors: {801 orange: 'orange',802 },803 borderColor: (theme) => ({804 foo: theme('colors.orange'),805 bar: theme('colors.red'),806 }),807 },808 },809 }810 const defaultConfig = {811 prefix: '-',812 important: false,813 separator: ':',814 content: [],815 theme: {816 colors: {817 cyan: 'cyan',818 magenta: 'magenta',819 yellow: 'yellow',820 },821 borderColor: (theme) => ({822 default: theme('colors.yellow', 'currentColor'),823 ...theme('colors'),824 }),825 },826 }827 const result = resolveConfig([userConfig, defaultConfig])828 expect(result).toMatchObject({829 prefix: '-',830 important: false,831 separator: ':',832 theme: {833 colors: {834 orange: 'orange',835 red: 'red',836 green: 'green',837 blue: 'blue',838 },839 borderColor: {840 default: 'currentColor',841 foo: 'orange',842 bar: 'red',843 orange: 'orange',844 red: 'red',845 green: 'green',846 blue: 'blue',847 },848 },849 })850})851test('lazily evaluated values have access to the config utils', () => {852 const userConfig = {853 theme: {854 inset: (theme) => theme('margin'),855 shift: (theme, { negative }) => ({856 ...theme('spacing'),857 ...negative(theme('spacing')),858 }),859 extend: {860 nudge: (theme, { negative }) => ({861 ...theme('spacing'),862 ...negative(theme('spacing')),863 }),864 },865 },866 }867 const defaultConfig = {868 prefix: '-',869 important: false,870 separator: ':',871 content: [],872 theme: {873 spacing: {874 1: '1px',875 2: '2px',876 3: '3px',877 4: '4px',878 },879 margin: (theme, { negative }) => ({880 ...theme('spacing'),881 ...negative(theme('spacing')),882 }),883 },884 }885 const result = resolveConfig([userConfig, defaultConfig])886 expect(result).toMatchObject({887 prefix: '-',888 important: false,889 separator: ':',890 theme: {891 spacing: {892 1: '1px',893 2: '2px',894 3: '3px',895 4: '4px',896 },897 inset: {898 '-1': '-1px',899 '-2': '-2px',900 '-3': '-3px',901 '-4': '-4px',902 1: '1px',903 2: '2px',904 3: '3px',905 4: '4px',906 },907 margin: {908 '-1': '-1px',909 '-2': '-2px',910 '-3': '-3px',911 '-4': '-4px',912 1: '1px',913 2: '2px',914 3: '3px',915 4: '4px',916 },917 shift: {918 '-1': '-1px',919 '-2': '-2px',920 '-3': '-3px',921 '-4': '-4px',922 1: '1px',923 2: '2px',924 3: '3px',925 4: '4px',926 },927 nudge: {928 '-1': '-1px',929 '-2': '-2px',930 '-3': '-3px',931 '-4': '-4px',932 1: '1px',933 2: '2px',934 3: '3px',935 4: '4px',936 },937 },938 })939})940test('the original theme is not mutated', () => {941 const userConfig = {942 theme: {943 extend: {944 colors: {945 orange: 'orange',946 },947 },948 },949 }950 const defaultConfig = {951 prefix: '-',952 important: false,953 separator: ':',954 content: [],955 theme: {956 colors: {957 cyan: 'cyan',958 magenta: 'magenta',959 yellow: 'yellow',960 },961 },962 }963 resolveConfig([userConfig, defaultConfig])964 expect(userConfig).toEqual({965 theme: {966 extend: {967 colors: {968 orange: 'orange',969 },970 },971 },972 })973})974test('custom properties are multiplied by -1 for negative values', () => {975 const userConfig = {976 theme: {977 spacing: {978 0: 0,979 1: '1px',980 2: '2px',981 3: '3px',982 4: '4px',983 auto: 'auto',984 foo: 'var(--foo)',985 bar: 'var(--bar, 500px)',986 baz: 'calc(50% - 10px)',987 qux: '10poops',988 },989 margin: (theme, { negative }) => ({990 ...theme('spacing'),991 ...negative(theme('spacing')),992 }),993 },994 }995 const defaultConfig = {996 prefix: '-',997 important: false,998 separator: ':',999 content: [],1000 theme: {},1001 }1002 const result = resolveConfig([userConfig, defaultConfig])1003 expect(result.theme.spacing).toEqual({1004 0: 0,1005 1: '1px',1006 2: '2px',1007 3: '3px',1008 4: '4px',1009 auto: 'auto',1010 foo: 'var(--foo)',1011 bar: 'var(--bar, 500px)',1012 baz: 'calc(50% - 10px)',1013 qux: '10poops',1014 })1015 expect(result.theme.margin).toEqual({1016 0: 0,1017 1: '1px',1018 2: '2px',1019 3: '3px',1020 4: '4px',1021 auto: 'auto',1022 foo: 'var(--foo)',1023 bar: 'var(--bar, 500px)',1024 baz: 'calc(50% - 10px)',1025 qux: '10poops',1026 '-0': '0',1027 '-1': '-1px',1028 '-2': '-2px',1029 '-3': '-3px',1030 '-4': '-4px',1031 '-foo': 'calc(var(--foo) * -1)',1032 '-bar': 'calc(var(--bar, 500px) * -1)',1033 '-baz': 'calc(calc(50% - 10px) * -1)',1034 '-qux': '-10poops',1035 })1036})1037test('more than two config objects can be resolved', () => {1038 const firstConfig = {1039 theme: {1040 extend: {1041 fontFamily: () => ({1042 code: ['Menlo', 'monospace'],1043 }),1044 colors: {1045 red: 'red',1046 },1047 backgroundColor: {1048 customBackgroundOne: '#bada55',1049 },1050 textDecorationColor: {1051 orange: 'orange',1052 },1053 },1054 },1055 }1056 const secondConfig = {1057 prefix: '-',1058 important: false,1059 separator: ':',1060 theme: {1061 extend: {1062 fontFamily: {1063 quote: ['Helvetica', 'serif'],1064 },1065 colors: {1066 green: 'green',1067 },1068 backgroundColor: {1069 customBackgroundTwo: '#facade',1070 },1071 textDecorationColor: (theme) => theme('colors'),1072 },1073 },1074 }1075 const thirdConfig = {1076 prefix: '-',1077 important: false,1078 separator: ':',1079 theme: {1080 extend: {1081 fontFamily: {1082 hero: ['Futura', 'sans-serif'],1083 },1084 colors: {1085 pink: 'pink',1086 },1087 backgroundColor: () => ({1088 customBackgroundThree: '#c0ffee',1089 }),1090 textDecorationColor: {1091 lime: 'lime',1092 },1093 },1094 },1095 }1096 const defaultConfig = {1097 prefix: '-',1098 important: false,1099 separator: ':',1100 content: [],1101 theme: {1102 fontFamily: {1103 body: ['Arial', 'sans-serif'],1104 display: ['Georgia', 'serif'],1105 },1106 colors: {1107 blue: 'blue',1108 },1109 backgroundColor: (theme) => theme('colors'),1110 },1111 }1112 const result = resolveConfig([firstConfig, secondConfig, thirdConfig, defaultConfig])1113 expect(result).toMatchObject({1114 prefix: '-',1115 important: false,1116 separator: ':',1117 theme: {1118 fontFamily: {1119 body: ['Arial', 'sans-serif'],1120 display: ['Georgia', 'serif'],1121 code: ['Menlo', 'monospace'],1122 quote: ['Helvetica', 'serif'],1123 hero: ['Futura', 'sans-serif'],1124 },1125 colors: {1126 red: 'red',1127 green: 'green',1128 blue: 'blue',1129 pink: 'pink',1130 },1131 backgroundColor: {1132 red: 'red',1133 green: 'green',1134 blue: 'blue',1135 pink: 'pink',1136 customBackgroundOne: '#bada55',1137 customBackgroundTwo: '#facade',1138 customBackgroundThree: '#c0ffee',1139 },1140 textDecorationColor: {1141 red: 'red',1142 green: 'green',1143 blue: 'blue',1144 pink: 'pink',1145 orange: 'orange',1146 lime: 'lime',1147 },1148 },1149 })1150})1151test('plugin config modifications are applied', () => {1152 const userConfig = {1153 plugins: [1154 {1155 config: {1156 prefix: 'tw-',1157 },1158 },1159 ],1160 }1161 const defaultConfig = {1162 prefix: '',1163 important: false,1164 separator: ':',1165 content: [],1166 theme: {1167 screens: {1168 mobile: '400px',1169 },1170 },1171 }1172 const result = resolveConfig([userConfig, defaultConfig])1173 expect(result).toMatchObject({1174 prefix: 'tw-',1175 important: false,1176 separator: ':',1177 theme: {1178 screens: {1179 mobile: '400px',1180 },1181 },1182 plugins: userConfig.plugins,1183 })1184})1185test('user config takes precedence over plugin config modifications', () => {1186 const userConfig = {1187 prefix: 'user-',1188 plugins: [1189 {1190 config: {1191 prefix: 'tw-',1192 },1193 },1194 ],1195 }1196 const defaultConfig = {1197 prefix: '',1198 important: false,1199 separator: ':',1200 content: [],1201 theme: {1202 screens: {1203 mobile: '400px',1204 },1205 },1206 }1207 const result = resolveConfig([userConfig, defaultConfig])1208 expect(result).toMatchObject({1209 prefix: 'user-',1210 important: false,1211 separator: ':',1212 theme: {1213 screens: {1214 mobile: '400px',1215 },1216 },1217 plugins: userConfig.plugins,1218 })1219})1220test('plugin config can register plugins that also have config', () => {1221 const userConfig = {1222 plugins: [1223 {1224 config: {1225 prefix: 'tw-',1226 plugins: [1227 {1228 config: {1229 important: true,1230 },1231 },1232 {1233 config: {1234 separator: '__',1235 },1236 },1237 ],1238 },1239 handler() {},1240 },1241 ],1242 }1243 const defaultConfig = {1244 prefix: '',1245 important: false,1246 separator: ':',1247 content: [],1248 theme: {1249 screens: {1250 mobile: '400px',1251 },1252 },1253 }1254 const result = resolveConfig([userConfig, defaultConfig])1255 expect(result).toMatchObject({1256 prefix: 'tw-',1257 important: true,1258 separator: '__',1259 theme: {1260 screens: {1261 mobile: '400px',1262 },1263 },1264 plugins: userConfig.plugins,1265 })1266})1267test('plugin configs take precedence over plugin configs registered by that plugin', () => {1268 const userConfig = {1269 plugins: [1270 {1271 config: {1272 prefix: 'outer-',1273 plugins: [1274 {1275 config: {1276 prefix: 'inner-',1277 },1278 },1279 ],1280 },1281 handler() {},1282 },1283 ],1284 }1285 const defaultConfig = {1286 prefix: '',1287 important: false,1288 separator: ':',1289 content: [],1290 theme: {1291 screens: {1292 mobile: '400px',1293 },1294 },1295 }1296 const result = resolveConfig([userConfig, defaultConfig])1297 expect(result).toMatchObject({1298 prefix: 'outer-',1299 important: false,1300 separator: ':',1301 theme: {1302 screens: {1303 mobile: '400px',1304 },1305 },1306 plugins: userConfig.plugins,1307 })1308})1309test('plugin theme extensions are added even if user overrides top-level theme config', () => {1310 const userConfig = {1311 theme: {1312 width: {1313 '1px': '1px',1314 },1315 },1316 plugins: [1317 {1318 config: {1319 theme: {1320 extend: {1321 width: {1322 '2px': '2px',1323 '3px': '3px',1324 },1325 },1326 },1327 },1328 handler() {},1329 },1330 ],1331 }1332 const defaultConfig = {1333 prefix: '',1334 important: false,1335 separator: ':',1336 content: [],1337 theme: {1338 width: {1339 sm: '1rem',1340 md: '2rem',1341 lg: '3rem',1342 },1343 screens: {1344 mobile: '400px',1345 },1346 },1347 }1348 const result = resolveConfig([userConfig, defaultConfig])1349 expect(result).toMatchObject({1350 prefix: '',1351 important: false,1352 separator: ':',1353 theme: {1354 width: {1355 '1px': '1px',1356 '2px': '2px',1357 '3px': '3px',1358 },1359 screens: {1360 mobile: '400px',1361 },1362 },1363 plugins: userConfig.plugins,1364 })1365})1366test('user theme extensions take precedence over plugin theme extensions with the same key', () => {1367 const userConfig = {1368 theme: {1369 extend: {1370 width: {1371 xl: '6rem',1372 },1373 },1374 },1375 plugins: [1376 {1377 config: {1378 theme: {1379 extend: {1380 width: {1381 xl: '4rem',1382 },1383 },1384 },1385 },1386 handler() {},1387 },1388 ],1389 }1390 const defaultConfig = {1391 prefix: '',1392 important: false,1393 separator: ':',1394 content: [],1395 theme: {1396 width: {1397 sm: '1rem',1398 md: '2rem',1399 lg: '3rem',1400 },1401 screens: {1402 mobile: '400px',1403 },1404 },1405 }1406 const result = resolveConfig([userConfig, defaultConfig])1407 expect(result).toMatchObject({1408 prefix: '',1409 important: false,1410 separator: ':',1411 theme: {1412 width: {1413 sm: '1rem',1414 md: '2rem',1415 lg: '3rem',1416 xl: '6rem',1417 },1418 screens: {1419 mobile: '400px',1420 },1421 },1422 plugins: userConfig.plugins,1423 })1424})1425test('extensions are applied in the right order', () => {1426 const userConfig = {1427 theme: {1428 extend: {1429 colors: {1430 grey: {1431 light: '#eee',1432 },1433 },1434 },1435 },1436 }1437 const otherConfig = {1438 theme: {1439 extend: {1440 colors: {1441 grey: {1442 light: '#ddd',1443 darker: '#111',1444 },1445 },1446 },1447 },1448 }1449 const anotherConfig = {1450 theme: {1451 extend: {1452 colors: {1453 grey: {1454 darker: '#222',1455 },1456 },1457 },1458 },1459 }1460 const defaultConfig = {1461 content: [],1462 theme: {1463 colors: {1464 grey: {1465 light: '#ccc',1466 dark: '#333',1467 },1468 },1469 },1470 }1471 const result = resolveConfig([userConfig, otherConfig, anotherConfig, defaultConfig])1472 expect(result).toMatchObject({1473 theme: {1474 colors: {1475 grey: {1476 light: '#eee',1477 dark: '#333',1478 darker: '#111',1479 },1480 },1481 },1482 })1483})1484test('core plugin configuration builds on the default list when starting with an empty object', () => {1485 const userConfig = {1486 corePlugins: { display: false },1487 }1488 const defaultConfig = {1489 prefix: '',1490 important: false,1491 separator: ':',1492 content: [],1493 theme: {},1494 corePlugins: {},1495 }1496 const result = resolveConfig([userConfig, defaultConfig])1497 expect(result).toMatchObject({1498 prefix: '',1499 important: false,1500 separator: ':',1501 theme: {},1502 corePlugins: corePluginList.filter((c) => c !== 'display'),1503 })1504})1505test('core plugins that are disabled by default can be enabled', () => {1506 const userConfig = {1507 corePlugins: { display: true },1508 }1509 const defaultConfig = {1510 presets: [],1511 prefix: '',1512 important: false,1513 separator: ':',1514 content: [],1515 theme: {},1516 corePlugins: { display: false },1517 }1518 const result = resolveConfig([userConfig, defaultConfig])1519 expect(result.corePlugins).toContain('display')1520})1521test('core plugin configurations stack', () => {1522 const userConfig = {1523 corePlugins: { display: false },1524 }1525 const otherConfig = {1526 corePlugins: ({ corePlugins }) => {1527 return [...corePlugins, 'margin']1528 },1529 }1530 const defaultConfig = {1531 prefix: '',1532 important: false,1533 separator: ':',1534 content: [],1535 theme: {},1536 corePlugins: ['float', 'display', 'padding'],1537 }1538 const result = resolveConfig([userConfig, otherConfig, defaultConfig])1539 expect(result).toMatchObject({1540 prefix: '',1541 important: false,1542 separator: ':',1543 theme: {},1544 corePlugins: ['float', 'padding', 'margin'],1545 })1546})1547test('plugins are merged', () => {1548 const userConfig = {1549 plugins: ['3'],1550 }1551 const otherConfig = {1552 plugins: ['2'],1553 }1554 const defaultConfig = {1555 plugins: ['1'],1556 prefix: '',1557 important: false,1558 separator: ':',1559 content: [],1560 theme: {},1561 }1562 const result = resolveConfig([userConfig, otherConfig, defaultConfig])1563 expect(result).toMatchObject({1564 prefix: '',1565 important: false,1566 separator: ':',1567 theme: {},1568 plugins: ['1', '2', '3'],1569 })1570})1571test('all helpers can be destructured from the first function argument', () => {1572 const userConfig = {1573 theme: {1574 example: ({ theme, colors, negative, breakpoints }) => ({1575 weight: theme('fontWeight.bold'),1576 black: colors.black,1577 white: colors.white,1578 ...negative(theme('spacing')),1579 ...breakpoints(theme('screens')),1580 }),1581 },1582 }1583 const defaultConfig = {1584 prefix: '-',1585 important: false,1586 separator: ':',1587 content: [],1588 theme: {1589 screens: {1590 sm: '640px',1591 md: '768px',1592 },1593 fontWeight: {1594 bold: 700,1595 },1596 spacing: {1597 0: '0px',1598 1: '1px',1599 2: '2px',1600 3: '3px',1601 4: '4px',1602 },1603 },1604 }1605 const result = resolveConfig([userConfig, defaultConfig])1606 expect(result).toMatchObject({1607 prefix: '-',1608 important: false,1609 separator: ':',1610 theme: {1611 example: {1612 weight: 700,1613 black: '#000',1614 white: '#fff',1615 '-1': '-1px',1616 '-2': '-2px',1617 '-3': '-3px',1618 '-4': '-4px',1619 'screen-sm': '640px',1620 'screen-md': '768px',1621 },1622 },1623 })...

Full Screen

Full Screen

init.js

Source:init.js Github

copy

Full Screen

1/**2 * Imports the config module3 * @module config4 */5import config from "../config.js";6/**7 * AmplitudeJS Core Module8 * @module core/Core9 */10import Core from "../core/core.js";11/**12 * AmplitudeJS SoundCloud Module13 * @module soundcloud/SoundCloud14 */15import SoundCloud from "../soundcloud/soundcloud.js";16/**17 * Imports the utilities used by the main module.18 */19/**20 * AmplitudeJS Config State Module21 * @module utilities/ConfigState22 */23import ConfigState from "../utilities/configState.js";24/**25 * AmplitudeJS Debug Module26 * @module utilities/Debug27 */28import Debug from "../utilities/debug.js";29/**30 * AmplitudeJS Checks Module31 * @module utilities/Checks32 */33import Checks from "../utilities/checks.js";34/**35 * AmplitudeJS Shuffler Module36 * @module utilities/Shuffler37 */38import Shuffler from "../utilities/shuffler.js";39/**40 * AmplitudeJS Events Module41 * @module events/Events42 */43import Events from "../events/events.js";44/**45 * AmplitudeJS FX Module46 * @module fx/Fx47 */48import Fx from "../fx/fx.js";49/**50 * AmplitudeJS Visualizations Module51 * @module fx/Visualizations52 */53import Visualizations from "../fx/visualizations.js";54/**55 * AmplitudeJS WaveForm Module56 * @module fx/WaveForm57 */58import WaveForm from "../fx/waveform.js";59/**60 * AmplitudeJS Audio Navigation Module.61 * @module utilities/AudioNavigation62 */63import AudioNavigation from "../utilities/audioNavigation.js";64/**65 * AmplitudeJS Callbacks Module66 * @module utilities/Callbacks67 */68import Callbacks from "../utilities/callbacks.js";69/**70 * AmplitudeJS Playlists Initializer Module71 * @module init/Playlists72 */73import PlaylistsInitializer from "./playlists.js";74/**75 * Imports the AmplitudeJS Shuffle Elements76 * @module visual/ShuffleElements77 */78import ShuffleElements from "../visual/shuffleElements.js";79/**80 * Imports the AmplitudeJS Mute Elements81 * @module visual/MuteElements82 */83import MuteElements from "../visual/muteElements.js";84/**85 * Imports the AmplitudeJS Volume Slider86 * @module visual/VolumeSliderElements87 */88import VolumeSliderElements from "../visual/volumeSliderElements.js";89/**90 * Imports the AmplitudeJS Time Elements91 * @module visual/TimeElements92 */93import TimeElements from "../visual/timeElements.js";94/**95 * Imports the AmplitudeJS Play/Pause Elements Module.96 * @module visual/PlayPauseElements97 */98import PlayPauseElements from "../visual/playPauseElements.js";99/**100 * Imports the AmplitudeJS MetaData Elements Module.101 * @module visual/MetaDataElements102 */103import MetaDataElements from "../visual/metaDataElements.js";104/**105 * Imports the AmplitudeJS PlaybackSpeedElements Module.106 * @module visual/PlayBackSpeedElements107 */108import PlaybackSpeedElements from "../visual/playbackSpeedElements.js";109/**110 * Imports the AmplitudeJS Repeat Element111 * @module visual/RepeatElements112 */113import RepeatElements from "../visual/repeatElements.js";114/**115 * AmplitudeJS Initializer Module. Helps with the handling of all of the116 * initialization for AmplitudeJS.117 *118 * @module init/Initializer119 */120let Initializer = (function() {121 /**122 * The main init function. The user will call this through123 * Amplitude.init({}) and pass in their settings.124 *125 * Public Accessor: Amplitude.init( user_config_json )126 * @access public127 * @param {object} userConfig - A JSON object of user defined values that help configure and initialize AmplitudeJS.128 */129 function initialize(userConfig) {130 let ready = false;131 /*132 Reset the config on init so we have a clean slate. This is if the133 user has to re-init.134 */135 ConfigState.resetConfig();136 /*137 Initialize event handlers on init. This will clear any old138 event handlers on the amplitude element and re-bind what is139 necessary.140 */141 Events.initialize();142 /*143 Initialize the callbacks we listen to for the audio object.144 */145 Callbacks.initialize();146 /*147 Initializes debugging right away so we can use it for the rest148 of the configuration.149 */150 config.debug = userConfig.debug != undefined ? userConfig.debug : false;151 /*152 Set default artwork, if specified.153 */154 setArt(userConfig)155 /*156 Checks to see if the user has songs defined.157 */158 if (userConfig.songs) {159 /*160 Checks to see if the user has some songs in the songs array.161 */162 if (userConfig.songs.length != 0) {163 /*164 Copies over the user defined songs. and prepares165 Amplitude for the rest of the configuration.166 */167 config.songs = userConfig.songs;168 /*169 Flag amplitude as ready.170 */171 ready = true;172 } else {173 Debug.writeMessage("Please add some songs, to your songs object!");174 }175 } else {176 Debug.writeMessage(177 "Please provide a songs object for AmplitudeJS to run!"178 );179 }180 /*181 Initializes the audio context. In this method it checks to see if the182 user wants to use visualizations or not before proceeding.183 */184 if (Fx.webAudioAPIAvailable()) {185 if( Fx.determineUsingAnyFX() ){186 /*187 Configure the Web Audio API If It's available.188 */189 Fx.configureWebAudioAPI();190 /*191 Activates the audio context after an event for the user.192 */193 document.documentElement.addEventListener(194 "mousedown", function(){195 if (config.context.state !== 'running') {196 config.context.resume();197 }198 });199 document.documentElement.addEventListener(200 "keydown", function(){201 if (config.context.state !== 'running') {202 config.context.resume();203 }204 });205 document.documentElement.addEventListener(206 "keyup", function(){207 if (config.context.state !== 'running') {208 config.context.resume();209 }210 });211 212 213 /*214 Set the user waveform settings if provided.215 */216 if (217 userConfig.waveforms != undefined &&218 userConfig.waveforms.sample_rate != undefined219 ) {220 config.waveforms.sample_rate = userConfig.waveforms.sample_rate;221 }222 /*223 Initialize the waveform.224 */225 WaveForm.init();226 /*227 If the user is registering visualizations on init,228 we set them right away.229 */230 if (231 userConfig.visualizations != undefined &&232 userConfig.visualizations.length > 0233 ) {234 /*235 Iterate over all of the visualizations and236 register them in our player.237 */238 for (let i = 0; i < userConfig.visualizations.length; i++) {239 Visualizations.register(240 userConfig.visualizations[i].object,241 userConfig.visualizations[i].params242 );243 }244 }245 }246 } else {247 Debug.writeMessage(248 "The Web Audio API is not available on this platform. We are using your defined backups!"249 );250 }251 /*252 Initialize default live settings253 */254 initializeDefaultLiveSettings();255 /*256 Initialize default song indexes257 */258 initializeDefaultSongIndexes();259 /*260 When the preliminary config is ready, we are ready to proceed.261 */262 if (ready) {263 /*264 Copies over the soundcloud information to the global config265 which will determine where we go from there.266 */267 config.soundcloud_client =268 userConfig.soundcloud_client != undefined269 ? userConfig.soundcloud_client270 : "";271 /*272 Checks if we want to use the art loaded from soundcloud.273 */274 config.soundcloud_use_art =275 userConfig.soundcloud_use_art != undefined276 ? userConfig.soundcloud_use_art277 : "";278 /*279 If the user provides a soundcloud client then we assume that280 there are URLs in their songs that will reference SoundCloud.281 We then copy over the user config they provided to the282 temp_user_config so we don't mess up the global or their configs283 and load the soundcloud information.284 */285 let tempUserConfig = {};286 /*287 If there's a soundcloud_client key set, we load the SoundCloud data288 for all of the songs in the array.289 */290 if (config.soundcloud_client != "") {291 tempUserConfig = userConfig;292 /*293 Load up SoundCloud for use with AmplitudeJS.294 */295 SoundCloud.loadSoundCloud(tempUserConfig);296 } else {297 /*298 The user is not using Soundcloud with Amplitude at this point299 so we just finish the configuration with the users's preferences.300 */301 setConfig(userConfig);302 }303 }304 /*305 Debug out what was initialized with AmplitudeJS.306 */307 Debug.writeMessage("Initialized With: ");308 Debug.writeMessage(config);309 }310 /**311 * Rebinds all of the elements in the display.312 *313 * Public Accessor: Amplitude.rebindDisplay()314 * @access public315 */316 function rebindDisplay() {317 Events.initialize();318 MetaDataElements.displayMetaData();319 }320 /**321 * Finishes the initalization of the config. Takes all of the user defined322 * parameters and makes sure they override the defaults. The important323 * config information is assigned in the publicInit() function.324 *325 * This function can be called from 2 different locations:326 * 1. Right away on init after the important settings are defined.327 *328 * 2. After all of the Soundcloud URLs are resolved properly and329 * soundcloud is configured. We will need the proper URLs from Soundcloud330 * to stream through Amplitude so we get those right away before we331 * set the information and the active song332 *333 * @access public334 * @param {object} userConfig - A JSON object of user defined values that help configure and initialize AmplitudeJS.335 */336 function setConfig(userConfig) {337 /*338 Checks if the user has any playlists defined. If they do339 we have to initialize the functionality for the playlists.340 */341 if (userConfig.playlists && countPlaylists(userConfig.playlists) > 0) {342 PlaylistsInitializer.initialize(userConfig.playlists);343 }344 /*345 Check to see if the user entered a start song346 */347 if (userConfig.start_song != undefined && userConfig.starting_playlist) {348 /*349 Ensure what has been entered is an integer.350 */351 if (Checks.isInt(userConfig.start_song)) {352 AudioNavigation.changeSong(353 config.songs[userConfig.start_song],354 userConfig.start_song355 );356 } else {357 Debug.writeMessage(358 "You must enter an integer index for the start song."359 );360 }361 } else {362 AudioNavigation.changeSong(config.songs[0], 0);363 }364 /*365 If the shuffle is on by default, shuffle the songs and366 switch to the shuffled song.367 */368 if (userConfig.shuffle_on != undefined && userConfig.shuffle_on) {369 config.shuffle_on = true;370 Shuffler.shuffleSongs();371 AudioNavigation.changeSong(config.shuffle_list[0], 0);372 }373 /*374 Allows the user to set whether they want to continue to the next song375 when the current song finishes or not. In any scenario that's not a playlist,376 contining to the next song may not be desired.377 */378 config.continue_next =379 userConfig.continue_next != undefined ? userConfig.continue_next : true;380 /*381 If the user defined a playback speed, we copy over their382 preference here, otherwise we default to normal playback383 speed of 1.0.384 */385 config.playback_speed =386 userConfig.playback_speed != undefined ? userConfig.playback_speed : 1.0;387 /*388 Sets the audio playback speed.389 */390 Core.setPlaybackSpeed(config.playback_speed);391 /*392 If the user wants the song to be pre-loaded for instant393 playback, they set it to true. By default it's set to just394 load the metadata.395 */396 config.audio.preload =397 userConfig.preload != undefined ? userConfig.preload : "auto";398 /*399 Initializes the user defined callbacks. This should be a JSON400 object that contains a key->value store of the callback name401 and the name of the function the user needs to call.402 */403 config.callbacks =404 userConfig.callbacks != undefined ? userConfig.callbacks : {};405 /*406 Initializes the user defined key bindings. This should be a JSON407 object that contains a key->value store of the key event number408 pressed and the method to be run.409 */410 config.bindings =411 userConfig.bindings != undefined ? userConfig.bindings : {};412 /*413 The user can define a starting volume in a range of 0-100 with414 0 being muted and 100 being the loudest. After the config is set415 Amplitude sets the active song's volume to the volume defined416 by the user.417 */418 config.volume = userConfig.volume != undefined ? userConfig.volume : 50;419 /*420 Sets the delay between songs if the user has it set. This should be in MS.421 */422 config.delay = userConfig.delay != undefined ? userConfig.delay : 0;423 /*424 The user can set the volume increment and decrement values between 1 and 100425 for when the volume up or down button is pressed. The default is an increase426 or decrease of 5.427 */428 config.volume_increment =429 userConfig.volume_increment != undefined430 ? userConfig.volume_increment431 : 5;432 config.volume_decrement =433 userConfig.volume_decrement != undefined434 ? userConfig.volume_decrement435 : 5;436 /*437 Set the volume to what is defined in the config. The user can define this,438 so we should set it up that way.439 */440 Core.setVolume(config.volume);441 /*442 Set default artwork, if specified443 */444 setArt(userConfig)445 /*446 Initialize the visual elements447 */448 initializeElements();449 /*450 If the user has selected a starting playlist, we need to set the starting playlist451 and sync the visuals452 */453 if (454 userConfig.starting_playlist != undefined &&455 userConfig.starting_playlist != ""456 ) {457 /*458 Set the active playlist to the starting playlist by the user459 */460 config.active_playlist = userConfig.starting_playlist;461 /*462 Check if the user defined a song to start with in the playlist.463 */464 if (465 userConfig.starting_playlist_song != undefined &&466 userConfig.starting_playlist_song != ""467 ) {468 /*469 Ensure the song is a valid index.470 */471 if (472 typeof userConfig.playlists[userConfig.starting_playlist].songs[473 parseInt(userConfig.starting_playlist_song)474 ] != undefined475 ) {476 /*477 Set the player to the song defined by the user.478 */479 AudioNavigation.changeSongPlaylist(480 config.active_playlist,481 userConfig.playlists[userConfig.starting_playlist].songs[482 parseInt(userConfig.starting_playlist_song)483 ],484 parseInt(userConfig.starting_playlist_song)485 );486 } else {487 /*488 Set the player to the first song in the playlist489 */490 AudioNavigation.changeSongPlaylist(491 config.active_playlist,492 userConfig.playlists[userConfig.starting_playlist].songs[0],493 0494 );495 /*496 Debug that the song index doesn't exist497 */498 Debug.writeMessage(499 "The index of " +500 userConfig.starting_playlist_song +501 " does not exist in the playlist " +502 userConfig.starting_playlist503 );504 }505 } else {506 /*507 Set the player to the first song in the playlist508 */509 AudioNavigation.changeSong(510 config.active_playlist,511 userConfig.playlists[userConfig.starting_playlist].songs[0],512 0513 );514 }515 /*516 Sync the main and song play pause buttons.517 */518 PlayPauseElements.sync();519 }520 /*521 Run after init callback522 */523 Callbacks.run("initialized");524 }525 /**526 * Sets the default_album_art and default_playlist_art from the527 * user supplied configuration.528 *529 * @access public530 * @param {object} userConfig - A JSON object of user defined values that help configure and initialize AmplitudeJS.531 */532 function setArt(userConfig){533 /*534 If the user defines default album art, this image will display if the active535 song doesn't have album art defined.536 */537 if (userConfig.default_album_art != undefined) {538 config.default_album_art = userConfig.default_album_art;539 } else {540 config.default_album_art = "";541 }542 /*543 If the user defines default playlist art, this image will display if the user544 tries to set up a playlist meta data image tag but doesn't have one defined.545 */546 if (userConfig.default_playlist_art != undefined) {547 config.default_playlist_art = userConfig.default_playlist_art;548 } else {549 config.default_playlist_art = "";550 }551 }552 /**553 * Initializes all of the elements on the page to the default starting point554 * to build from there.555 *556 * @access private557 */558 function initializeElements() {559 /*560 Visually sync the shuffle statuses561 */562 ShuffleElements.syncMain();563 /*564 Sync Mute Elements.565 */566 MuteElements.setMuted(config.volume == 0 ? true : false);567 /*568 Sync Volume Slider Elements569 */570 VolumeSliderElements.sync();571 /*572 Syncs all of the playback speed elements.573 */574 PlaybackSpeedElements.sync();575 /*576 Syncs all of the visual time elements to 00.577 */578 TimeElements.resetCurrentTimes();579 /*580 Sets all of the play pause buttons to pause.581 */582 PlayPauseElements.syncToPause();583 /*584 Sets the meta data for the songs automatically.585 */586 MetaDataElements.syncMetaData();587 /*588 Sets the repeat buttons automatically.589 */590 RepeatElements.syncRepeatSong();591 }592 /**593 * Counts the number of playlists the user has configured. This ensures594 * that the user has at least 1 playlist so we can validate the songs595 * defined in the playlist are correct and they didn't enter an invalid596 * ID.597 *598 * @access private599 * @param {object} playlists -600 */601 function countPlaylists(playlists) {602 /*603 Initialize the placeholders to iterate through the playlists604 and find out how many we have to account for.605 */606 let size = 0,607 key;608 /*609 Iterate over playlists and if the user has the playlist defined,610 increment the size of playlists.611 */612 for (key in playlists) {613 if (playlists.hasOwnProperty(key)) {614 size++;615 }616 }617 /*618 Debug how many playlists are in the config.619 */620 Debug.writeMessage("You have " + size + " playlist(s) in your config");621 /*622 Return the number of playlists in the config.623 */624 return size;625 }626 /**627 * Intializes the default live settings for all of the songs.628 *629 * @access private630 */631 function initializeDefaultLiveSettings() {632 for (let i = 0; i < config.songs.length; i++) {633 if (config.songs[i].live == undefined) {634 config.songs[i].live = false;635 }636 }637 }638 /** 639 * Initializes the index of the song in the songs array so640 * we can reference it if needed641 * 642 * @access private643 */644 function initializeDefaultSongIndexes(){645 for (let i = 0; i < config.songs.length; i++) {646 config.songs[i].index = i;647 }648 }649 /*650 Returns the publicly accessible methods651 */652 return {653 initialize: initialize,654 setConfig: setConfig,655 rebindDisplay: rebindDisplay656 };657})();...

Full Screen

Full Screen

config.ts

Source:config.ts Github

copy

Full Screen

1import path from 'path'2import fs from 'fs-extra'3// picocolors 是一个可以在终端修改输出字符样式的 npm 包,说直白点就是给字符添加颜色;(https://www.php.cn/toutiao-494426.html)4import c from 'picocolors'5// fast-glob 是一个快速批量导入、读取文件的库;vite 源码中也有用到6import fg from 'fast-glob'7import {8 normalizePath,9 UserConfig as ViteConfig,10 mergeConfig as mergeViteConfig,11 loadConfigFromFile12} from 'vite'13import { Options as VuePluginOptions } from '@vitejs/plugin-vue'14import {15 SiteData,16 HeadConfig,17 LocaleConfig,18 DefaultTheme,19 APPEARANCE_KEY,20 createLangDictionary,21 CleanUrlsMode,22 PageData23} from './shared'24import { DEFAULT_THEME_PATH } from './alias'25import { MarkdownOptions } from './markdown/markdown'26// debug.js 是用于 Web 开发的可嵌入 JavaScript 调试器。它允许您在没有 F12 工具的情况下轻松调试。27import _debug from 'debug'28export { resolveSiteDataByRoute } from './shared'29const debug = _debug('vitepress:config')30export interface UserConfig<ThemeConfig = any> {31 extends?: RawConfigExports<ThemeConfig>32 base?: string33 lang?: string34 title?: string35 titleTemplate?: string | boolean36 description?: string37 head?: HeadConfig[]38 appearance?: boolean39 themeConfig?: ThemeConfig40 locales?: Record<string, LocaleConfig>41 markdown?: MarkdownOptions42 lastUpdated?: boolean43 /**44 * Options to pass on to `@vitejs/plugin-vue`45 */46 vue?: VuePluginOptions47 /**48 * Vite config49 */50 vite?: ViteConfig51 srcDir?: string52 srcExclude?: string[]53 outDir?: string54 shouldPreload?: (link: string, page: string) => boolean55 /**56 * Configure the scroll offset when the theme has a sticky header.57 * Can be a number or a selector element to get the offset from.58 */59 scrollOffset?: number | string60 /**61 * Enable MPA / zero-JS mode.62 * @experimental63 */64 mpa?: boolean65 /**66 * Don't fail builds due to dead links.67 *68 * @default false69 */70 ignoreDeadLinks?: boolean71 /**72 * @experimental73 * Remove '.html' from URLs and generate clean directory structure.74 *75 * Available Modes:76 * - `disabled`: generates `/foo.html` for every `/foo.md` and shows `/foo.html` in browser77 * - `without-subfolders`: generates `/foo.html` for every `/foo.md` but shows `/foo` in browser78 * - `with-subfolders`: generates `/foo/index.html` for every `/foo.md` and shows `/foo` in browser79 *80 * @default 'disabled'81 */82 cleanUrls?: CleanUrlsMode83 /**84 * Build end hook: called when SSG finish.85 * @param siteConfig The resolved configuration.86 */87 buildEnd?: (siteConfig: SiteConfig) => Promise<void>88 /**89 * HTML transform hook: runs before writing HTML to dist.90 */91 transformHtml?: (92 code: string,93 id: string,94 ctx: {95 siteConfig: SiteConfig96 siteData: SiteData97 pageData: PageData98 title: string99 description: string100 head: HeadConfig[]101 content: string102 }103 ) => Promise<string | void>104}105export type RawConfigExports<ThemeConfig = any> =106 | UserConfig<ThemeConfig>107 | Promise<UserConfig<ThemeConfig>>108 | (() => UserConfig<ThemeConfig> | Promise<UserConfig<ThemeConfig>>)109export interface SiteConfig<ThemeConfig = any>110 extends Pick<111 UserConfig,112 | 'markdown'113 | 'vue'114 | 'vite'115 | 'shouldPreload'116 | 'mpa'117 | 'lastUpdated'118 | 'ignoreDeadLinks'119 | 'cleanUrls'120 | 'buildEnd'121 | 'transformHtml'122 > {123 root: string124 srcDir: string125 site: SiteData<ThemeConfig>126 configPath: string | undefined127 configDeps: string[]128 themeDir: string129 outDir: string130 tempDir: string131 pages: string[]132}133const resolve = (root: string, file: string) =>134 normalizePath(path.resolve(root, `.vitepress`, file))135/**136 * Type config helper137 * 为了更好的类型提示,没有什么其他效果138 * https://vitepress.vuejs.org/config/introduction#config-intellisense139 */140export function defineConfig(config: UserConfig<DefaultTheme.Config>) {141 return config142}143/**144 * Type config helper for custom theme config145 */146export function defineConfigWithTheme<ThemeConfig>(147 config: UserConfig<ThemeConfig>148) {149 return config150}151export async function resolveConfig(152 root: string = process.cwd(),153 command: 'serve' | 'build' = 'serve',154 mode = 'development'155): Promise<SiteConfig> {156 const [userConfig, configPath, configDeps] = await resolveUserConfig(157 root,158 command,159 mode160 )161 const site = await resolveSiteData(root, userConfig)162 const srcDir = path.resolve(root, userConfig.srcDir || '.')163 const outDir = userConfig.outDir164 ? path.resolve(root, userConfig.outDir)165 : resolve(root, 'dist')166 // resolve theme path167 const userThemeDir = resolve(root, 'theme')168 const themeDir = (await fs.pathExists(userThemeDir))169 ? userThemeDir170 : DEFAULT_THEME_PATH171 // Important: fast-glob doesn't guarantee order of the returned files.172 // We must sort the pages so the input list to rollup is stable across173 // builds - otherwise different input order could result in different exports174 // order in shared chunks which in turns invalidates the hash of every chunk!175 // JavaScript built-in sort() is mandated to be stable as of ES2019 and176 // supported in Node 12+, which is required by Vite.177 const pages = (178 await fg(['**.md'], {179 cwd: srcDir,180 ignore: ['**/node_modules', ...(userConfig.srcExclude || [])]181 })182 ).sort()183 const config: SiteConfig = {184 root,185 srcDir,186 site,187 themeDir,188 pages,189 configPath,190 configDeps,191 outDir,192 tempDir: resolve(root, '.temp'),193 markdown: userConfig.markdown,194 lastUpdated: userConfig.lastUpdated,195 vue: userConfig.vue,196 vite: userConfig.vite,197 shouldPreload: userConfig.shouldPreload,198 mpa: !!userConfig.mpa,199 ignoreDeadLinks: userConfig.ignoreDeadLinks,200 cleanUrls: userConfig.cleanUrls || 'disabled',201 buildEnd: userConfig.buildEnd,202 transformHtml: userConfig.transformHtml203 }204 return config205}206const supportedConfigExtensions = ['js', 'ts', 'cjs', 'mjs', 'cts', 'mts']207async function resolveUserConfig(208 root: string,209 command: 'serve' | 'build',210 mode: string211): Promise<[UserConfig, string | undefined, string[]]> {212 // load user config213 const configPath = supportedConfigExtensions214 .map((ext) => resolve(root, `config.${ext}`))215 .find(fs.pathExistsSync)216 let userConfig: RawConfigExports = {}217 let configDeps: string[] = []218 if (!configPath) {219 debug(`no config file found.`)220 } else {221 const configExports = await loadConfigFromFile(222 { command, mode },223 configPath,224 root225 )226 if (configExports) {227 userConfig = configExports.config228 configDeps = configExports.dependencies.map((file) =>229 normalizePath(path.resolve(file))230 )231 }232 debug(`loaded config at ${c.yellow(configPath)}`)233 }234 return [await resolveConfigExtends(userConfig), configPath, configDeps]235}236async function resolveConfigExtends(237 config: RawConfigExports238): Promise<UserConfig> {239 const resolved = await (typeof config === 'function' ? config() : config)240 if (resolved.extends) {241 const base = await resolveConfigExtends(resolved.extends)242 return mergeConfig(base, resolved)243 }244 return resolved245}246function mergeConfig(a: UserConfig, b: UserConfig, isRoot = true) {247 const merged: Record<string, any> = { ...a }248 for (const key in b) {249 const value = b[key as keyof UserConfig]250 if (value == null) {251 continue252 }253 const existing = merged[key]254 if (Array.isArray(existing) && Array.isArray(value)) {255 merged[key] = [...existing, ...value]256 continue257 }258 if (isObject(existing) && isObject(value)) {259 if (isRoot && key === 'vite') {260 merged[key] = mergeViteConfig(existing, value)261 } else {262 merged[key] = mergeConfig(existing, value, false)263 }264 continue265 }266 merged[key] = value267 }268 return merged269}270function isObject(value: unknown): value is Record<string, any> {271 return Object.prototype.toString.call(value) === '[object Object]'272}273export async function resolveSiteData(274 root: string,275 userConfig?: UserConfig,276 command: 'serve' | 'build' = 'serve',277 mode = 'development'278): Promise<SiteData> {279 userConfig = userConfig || (await resolveUserConfig(root, command, mode))[0]280 return {281 lang: userConfig.lang || 'en-US',282 title: userConfig.title || 'VitePress',283 titleTemplate: userConfig.titleTemplate,284 description: userConfig.description || 'A VitePress site',285 base: userConfig.base ? userConfig.base.replace(/([^/])$/, '$1/') : '/',286 head: resolveSiteDataHead(userConfig),287 appearance: userConfig.appearance ?? true,288 themeConfig: userConfig.themeConfig || {},289 locales: userConfig.locales || {},290 langs: createLangDictionary(userConfig),291 scrollOffset: userConfig.scrollOffset || 90,292 cleanUrls: userConfig.cleanUrls || 'disabled'293 }294}295function resolveSiteDataHead(userConfig?: UserConfig): HeadConfig[] {296 const head = userConfig?.head ?? []297 // add inline script to apply dark mode, if user enables the feature.298 // this is required to prevent "flush" on initial page load.299 if (userConfig?.appearance ?? true) {300 head.push([301 'script',302 { id: 'check-dark-light' },303 `304 ;(() => {305 const saved = localStorage.getItem('${APPEARANCE_KEY}')306 const prefereDark = window.matchMedia('(prefers-color-scheme: dark)').matches307 if (!saved || saved === 'auto' ? prefereDark : saved === 'dark') {308 document.documentElement.classList.add('dark')309 }310 })()311 `312 ])313 }314 return head...

Full Screen

Full Screen

index.js

Source:index.js Github

copy

Full Screen

1import { RouteTransitions, Skins } from '@core/enums'2export const defineThemeConfig = userConfig => {3 const localStorageTheme = localStorage.getItem(`${userConfig.app.title}-theme`)4 const localStorageIsVerticalNavSemiDark = localStorage.getItem(`${userConfig.app.title}-isVerticalNavSemiDark`)5 const localStorageSkin = (() => {6 const storageValue = localStorage.getItem(`${userConfig.app.title}-skin`)7 8 return Object.values(Skins).find(v => v === storageValue)9 })()10 const localStorageTransition = (() => {11 const storageValue = localStorage.getItem(`${userConfig.app.title}-transition`)12 13 return Object.values(RouteTransitions).find(v => v === storageValue)14 })()15 16 return {17 themeConfig: {18 app: {19 title: userConfig.app.title,20 logo: userConfig.app.logo,21 contentWidth: ref(userConfig.app.contentWidth),22 contentLayoutNav: ref(userConfig.app.contentLayoutNav),23 overlayNavFromBreakpoint: userConfig.app.overlayNavFromBreakpoint,24 enableI18n: userConfig.app.enableI18n,25 theme: ref(localStorageTheme || userConfig.app.theme),26 isRtl: ref(userConfig.app.isRtl),27 skin: ref(localStorageSkin || userConfig.app.skin),28 routeTransition: ref(localStorageTransition || userConfig.app.routeTransition),29 iconRenderer: userConfig.app.iconRenderer,30 },31 navbar: {32 type: ref(userConfig.navbar.type),33 navbarBlur: ref(userConfig.navbar.navbarBlur),34 },35 footer: { type: ref(userConfig.footer.type) },36 verticalNav: {37 isVerticalNavCollapsed: ref(userConfig.verticalNav.isVerticalNavCollapsed),38 defaultNavItemIconProps: userConfig.verticalNav.defaultNavItemIconProps,39 isVerticalNavSemiDark: ref(localStorageIsVerticalNavSemiDark ? JSON.parse(localStorageIsVerticalNavSemiDark) : userConfig.verticalNav.isVerticalNavSemiDark),40 },41 horizontalNav: {42 type: ref(userConfig.horizontalNav.type),43 transition: userConfig.horizontalNav.transition,44 },45 icons: {46 chevronDown: userConfig.icons.chevronDown,47 chevronRight: userConfig.icons.chevronRight,48 close: userConfig.icons.close,49 verticalNavPinned: userConfig.icons.verticalNavPinned,50 verticalNavUnPinned: userConfig.icons.verticalNavUnPinned,51 sectionTitlePlaceholder: userConfig.icons.sectionTitlePlaceholder,52 },53 },54 layoutConfig: {55 app: {56 title: userConfig.app.title,57 logo: userConfig.app.logo,58 contentWidth: userConfig.app.contentWidth,59 contentLayoutNav: userConfig.app.contentLayoutNav,60 overlayNavFromBreakpoint: userConfig.app.overlayNavFromBreakpoint,61 enableI18n: userConfig.app.enableI18n,62 isRtl: userConfig.app.isRtl,63 iconRenderer: userConfig.app.iconRenderer,64 },65 navbar: {66 type: userConfig.navbar.type,67 navbarBlur: userConfig.navbar.navbarBlur,68 },69 footer: {70 type: userConfig.footer.type,71 },72 verticalNav: {73 isVerticalNavCollapsed: userConfig.verticalNav.isVerticalNavCollapsed,74 defaultNavItemIconProps: userConfig.verticalNav.defaultNavItemIconProps,75 },76 horizontalNav: {77 type: userConfig.horizontalNav.type,78 transition: userConfig.horizontalNav.transition,79 },80 icons: {81 chevronDown: userConfig.icons.chevronDown,82 chevronRight: userConfig.icons.chevronRight,83 close: userConfig.icons.close,84 verticalNavPinned: userConfig.icons.verticalNavPinned,85 verticalNavUnPinned: userConfig.icons.verticalNavUnPinned,86 sectionTitlePlaceholder: userConfig.icons.sectionTitlePlaceholder,87 },88 },89 }...

Full Screen

Full Screen

user.service.ts

Source:user.service.ts Github

copy

Full Screen

1import { Injectable } from '@angular/core';2import { UserConfig } from '../models';3import SimpleCrypto from "simple-crypto-js";4import { HttpClient } from '@angular/common/http';5@Injectable()6export class UserService {7 constructor(private _http: HttpClient) { }8 userConfig: UserConfig;9 rewardsBaseUrl = 'https://tidymail.io/.netlify/functions/addemail?e=';10 createOrLoadConfig() {11 var config = localStorage.getItem('config');12 if (config == null) {13 var randomsecret = SimpleCrypto.generateRandom();14 this.userConfig = new UserConfig();15 this.userConfig.firsttime = true;16 this.userConfig.token = randomsecret;17 this.userConfig.autoSync = true;18 this.userConfig.showDeleteConfirm = true;19 } else {20 this.userConfig = JSON.parse(config);21 if(this.userConfig.password !== undefined)22 this.userConfig.password = this.decrypt(this.userConfig.password);23 }24 return this.userConfig;25 }26 encrypt(str: string) {27 var simpleCrypto = new SimpleCrypto(this.userConfig.token);28 return simpleCrypto.encrypt(str).toString();29 }30 decrypt(enc: string) {31 var simpleCrypto = new SimpleCrypto(this.userConfig.token);32 return simpleCrypto.decrypt(enc).toString();33 }34 saveLastUid(uid:number) {35 this.userConfig.lastUidProcessed = uid;36 this.save(this.userConfig);37 }38 storeImapSettings(host, port, username, password, isGmailProvider) {39 this.userConfig.imapurl = host;40 this.userConfig.imapport = parseInt(port);41 this.userConfig.username = username;42 this.userConfig.password = this.encrypt(password);43 this.userConfig.isGmailProvider = isGmailProvider;44 this.userConfig.firsttime = false;45 return new Promise<UserConfig>(46 (resolve, reject) => {47 localStorage.setItem('config', JSON.stringify(this.userConfig));48 resolve(this.userConfig);49 }50 )51 }52 reset() {53 localStorage.removeItem('config');54 }55 getConfig() {56 return this.userConfig;57 }58 registerRewards(email:string) {59 return this._http.get<any>(this.rewardsBaseUrl + email).toPromise();60 }61 public save(userConfig:UserConfig, password:string = null) {62 if(password != null) {63 userConfig.password = this.encrypt(password);64 } else {65 userConfig.password = this.encrypt(userConfig.password);66 }67 localStorage.setItem('config', JSON.stringify(userConfig));68 if(password != null) {69 userConfig.password = password;70 } else {71 userConfig.password = this.decrypt(userConfig.password);72 }73 }...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var bestPractice = require('bestpractice');2var bp = new bestPractice();3bp.userConfig('config.json', function(err, data){4 if(err){5 console.log(err);6 }7 else{8 console.log(data);9 }10});11var bestPractice = require('bestpractice');12var bp = new bestPractice();13bp.userConfig('config.json', 'config.json', function(err, data){14 if(err){15 console.log(err);16 }17 else{18 console.log(data);19 }20});21var bestPractice = require('bestpractice');22var bp = new bestPractice();23bp.userConfig('config.json', 'config.json', 'config.json', function(err, data){24 if(err){25 console.log(err);26 }27 else{28 console.log(data);29 }30});31var bestPractice = require('bestpractice');32var bp = new bestPractice();33bp.userConfig('config.json', 'config.json', 'config.json', 'config.json', function(err, data){34 if(err){35 console.log(err);36 }37 else{38 console.log(data);39 }40});41var bestPractice = require('bestpractice');42var bp = new bestPractice();43bp.userConfig('config.json', 'config.json', 'config.json', 'config.json', 'config.json', function(err, data){44 if(err){45 console.log(err);46 }47 else{48 console.log(data);49 }50});51var bestPractice = require('bestpractice');52var bp = new bestPractice();53bp.userConfig('config.json', 'config.json', 'config.json', 'config.json', 'config.json', 'config.json', function(err, data){54 if(err){55 console.log(err);56 }57 else{58 console.log(data);59 }60});61var bestPractice = require('bestpractice');62var bp = new bestPractice();63bp.userConfig('config.json

Full Screen

Using AI Code Generation

copy

Full Screen

1var BestPractice = require('./bestPractice');2var bp = new BestPractice();3bp.userConfig('test');4var BestPractice = require('./bestPractice');5var bp = new BestPractice();6bp.userConfig('test');7var BestPractice = require('./bestPractice');8var bp = new BestPractice();9bp.userConfig('test');10var BestPractice = require('./bestPractice');11var bp = new BestPractice();12bp.userConfig('test');13var BestPractice = require('./bestPractice');14var bp = new BestPractice();15bp.userConfig('test');16var BestPractice = require('./bestPractice');17var bp = new BestPractice();18bp.userConfig('test');19var BestPractice = require('./bestPractice');20var bp = new BestPractice();21bp.userConfig('test');22var BestPractice = require('./bestPractice');23var bp = new BestPractice();24bp.userConfig('test');25var BestPractice = require('./bestPractice');26var bp = new BestPractice();27bp.userConfig('test');28var BestPractice = require('./bestPractice');29var bp = new BestPractice();30bp.userConfig('

Full Screen

Using AI Code Generation

copy

Full Screen

1var bestBuy = new BestBuy();2var config = new UserConfig();3var input = new UserInput();4var output = new UserOutput();5var userInput = "";6document.getElementById("searchButton").addEventListener("click", function() {7 userInput = input.getInput();8 bestBuy.userConfig(userInput);9 output.userConfig(userInput);10});11document.getElementById("clearButton").addEventListener("click", function() {12 output.clear();13});14document.getElementById("searchBox").addEventListener("keyup", function(event) {15 if (event.keyCode === 13) {16 userInput = input.getInput();17 bestBuy.userConfig(userInput);18 output.userConfig(userInput);19 }20});21function UserInput() {22 this.getInput = function() {23 var input = document.getElementById("searchBox").value;24 return input;25 };26}27function BestBuy() {

Full Screen

Using AI Code Generation

copy

Full Screen

1var BestBuyService = require('./BestBuyService');2var service = new BestBuyService();3service.userConfig(function(data) {4 console.log(data);5});6function BestBuyService() {7 this.userConfig = function(callback) {8 var request = require('request');9 request(url, function(err, res, body) {10 if (err) {11 console.log(err);12 } else {13 var data = JSON.parse(body);14 callback(data);15 }16 });17 };18 this.getProducts = function(callback) {19 var request = require('request');20 request(url, function(err, res, body) {21 if (err) {22 console.log(err);23 } else {24 var data = JSON.parse(body);25 callback(data);26 }27 });28 };29}30module.exports = BestBuyService;31var BestBuyService = require('./BestBuyService');32var service = new BestBuyService();33service.getProducts(function(data) {34 console.log(data);35});36function BestBuyService() {37 this.userConfig = function(callback) {38 var request = require('request');39 request(url, function(err, res, body) {

Full Screen

Using AI Code Generation

copy

Full Screen

1import {BestBuy} from './bestbuy.js';2import {Product} from './product.js';3let config = BestBuy.userConfig();4let products = BestBuy.getProducts(config);5let productList = [];6for (let product of products) {7 let p = new Product(product);8 productList.push(p);9}10console.log(productList);11document.getElementById("products").innerHTML = productList.join("");12document.getElementById("productsTable").innerHTML = Product.toTable(productList);13document.getElementById("productsList").innerHTML = Product.toList(productList);14document.getElementById("productsGrid").innerHTML = Product.toGrid(productList);15document.getElementById("productsCarousel").innerHTML = Product.toCarousel(productList);16document.getElementById("productsCarousel2").innerHTML = Product.toCarousel2(productList);17document.getElementById("productsCarousel3").innerHTML = Product.toCarousel3(productList);18document.getElementById("productsCarousel4").innerHTML = Product.toCarousel4(productList);19document.getElementById("productsCarousel5").innerHTML = Product.toCarousel5(productList);20document.getElementById("productsCarousel6").innerHTML = Product.toCarousel6(productList);21document.getElementById("productsCarousel7").innerHTML = Product.toCarousel7(productList);22document.getElementById("productsCarousel8").innerHTML = Product.toCarousel8(productList);23document.getElementById("productsCarousel9").innerHTML = Product.toCarousel9(productList);24document.getElementById("productsCarousel10").innerHTML = Product.toCarousel10(productList);

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Best automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful