| 1 |
/** |
| 2 |
* Tests for countdown-style utility functions |
| 3 |
*/ |
| 4 |
import { |
| 5 |
toStyleObject, |
| 6 |
getContainerStyle, |
| 7 |
getBoxStyle, |
| 8 |
replaceVariables, |
| 9 |
calculateTimeLeft, |
| 10 |
getTimeUnits, |
| 11 |
buildDefaultCountdownState, |
| 12 |
} from '../countdown-style'; |
| 13 |
|
| 14 |
describe('countdown-style utilities', () => { |
| 15 |
describe('toStyleObject', () => { |
| 16 |
it('should convert kebab-case to camelCase', () => { |
| 17 |
const input = { |
| 18 |
'font-size': '14px', |
| 19 |
'font-weight': 600, |
| 20 |
'text-align': 'center', |
| 21 |
}; |
| 22 |
const result = toStyleObject(input); |
| 23 |
expect(result).toEqual({ |
| 24 |
fontSize: '14px', |
| 25 |
fontWeight: 600, |
| 26 |
textAlign: 'center', |
| 27 |
}); |
| 28 |
}); |
| 29 |
|
| 30 |
it('should skip specified keys like text, isChain, radius', () => { |
| 31 |
const input = { |
| 32 |
text: 'Hello', |
| 33 |
isChain: true, |
| 34 |
radius: { 'top-left': '6px' }, |
| 35 |
color: '#FFFFFF', |
| 36 |
}; |
| 37 |
const result = toStyleObject(input); |
| 38 |
expect(result).toEqual({ color: '#FFFFFF' }); |
| 39 |
expect(result.text).toBeUndefined(); |
| 40 |
expect(result.isChain).toBeUndefined(); |
| 41 |
expect(result.radius).toBeUndefined(); |
| 42 |
}); |
| 43 |
|
| 44 |
it('should return empty object for null/undefined input', () => { |
| 45 |
expect(toStyleObject(null)).toEqual({}); |
| 46 |
expect(toStyleObject(undefined)).toEqual({}); |
| 47 |
}); |
| 48 |
}); |
| 49 |
|
| 50 |
describe('getContainerStyle', () => { |
| 51 |
it('should apply border radius from radius object', () => { |
| 52 |
const container = { |
| 53 |
background: '#FF0000', |
| 54 |
radius: { |
| 55 |
'top-left': '6px', |
| 56 |
'top-right': '6px', |
| 57 |
'bottom-right': '6px', |
| 58 |
'bottom-left': '6px', |
| 59 |
}, |
| 60 |
border: 0, |
| 61 |
'border-color': 'rgba(0, 0, 0, 0)', |
| 62 |
}; |
| 63 |
const result = getContainerStyle(container); |
| 64 |
expect(result.borderRadius).toBe('6px 6px 6px 6px'); |
| 65 |
}); |
| 66 |
|
| 67 |
it('should apply border styles', () => { |
| 68 |
const container = { |
| 69 |
border: 2, |
| 70 |
'border-color': '#000000', |
| 71 |
}; |
| 72 |
const result = getContainerStyle(container); |
| 73 |
expect(result.borderWidth).toBe('2px'); |
| 74 |
expect(result.borderStyle).toBe('solid'); |
| 75 |
expect(result.borderColor).toBe('#000000'); |
| 76 |
}); |
| 77 |
|
| 78 |
it('should return empty object for null input', () => { |
| 79 |
expect(getContainerStyle(null)).toEqual({}); |
| 80 |
}); |
| 81 |
}); |
| 82 |
|
| 83 |
describe('getBoxStyle', () => { |
| 84 |
it('should apply box styles with border radius', () => { |
| 85 |
const box = { |
| 86 |
background: '#FFFFFF', |
| 87 |
padding: '8px 12px', |
| 88 |
radius: { |
| 89 |
'top-left': '2px', |
| 90 |
'top-right': '2px', |
| 91 |
'bottom-right': '2px', |
| 92 |
'bottom-left': '2px', |
| 93 |
}, |
| 94 |
border: 1, |
| 95 |
'border-color': '#CCCCCC', |
| 96 |
}; |
| 97 |
const result = getBoxStyle(box); |
| 98 |
expect(result.background).toBe('#FFFFFF'); |
| 99 |
expect(result.padding).toBe('8px 12px'); |
| 100 |
expect(result.borderRadius).toBe('2px 2px 2px 2px'); |
| 101 |
expect(result.borderWidth).toBe('1px'); |
| 102 |
}); |
| 103 |
|
| 104 |
it('should return empty object for null input', () => { |
| 105 |
expect(getBoxStyle(null)).toEqual({}); |
| 106 |
}); |
| 107 |
}); |
| 108 |
|
| 109 |
describe('replaceVariables', () => { |
| 110 |
it('should replace [discounted_percentage] with sample value', () => { |
| 111 |
const text = 'Save [discounted_percentage] today!'; |
| 112 |
expect(replaceVariables(text)).toBe('Save 20% today!'); |
| 113 |
}); |
| 114 |
|
| 115 |
it('should replace [discount_amount] with sample value', () => { |
| 116 |
const text = 'You save [discount_amount]'; |
| 117 |
expect(replaceVariables(text)).toBe('You save $50'); |
| 118 |
}); |
| 119 |
|
| 120 |
it('should replace [remaining_quantity] with sample value', () => { |
| 121 |
const text = 'Only [remaining_quantity] left!'; |
| 122 |
expect(replaceVariables(text)).toBe('Only 2 left!'); |
| 123 |
}); |
| 124 |
|
| 125 |
it('should replace [remaining_amount] with sample value', () => { |
| 126 |
const text = 'Add [remaining_amount] more'; |
| 127 |
expect(replaceVariables(text)).toBe('Add $25 more'); |
| 128 |
}); |
| 129 |
|
| 130 |
it('should replace multiple variables', () => { |
| 131 |
const text = '[discounted_percentage] OFF - Save [discount_amount]!'; |
| 132 |
expect(replaceVariables(text)).toBe('20% OFF - Save $50!'); |
| 133 |
}); |
| 134 |
|
| 135 |
it('should return empty string for null/undefined', () => { |
| 136 |
expect(replaceVariables(null)).toBe(''); |
| 137 |
expect(replaceVariables(undefined)).toBe(''); |
| 138 |
}); |
| 139 |
}); |
| 140 |
|
| 141 |
describe('calculateTimeLeft', () => { |
| 142 |
it('should return default values for past date', () => { |
| 143 |
const pastDate = '2020-01-01T00:00:00'; |
| 144 |
const result = calculateTimeLeft(pastDate); |
| 145 |
expect(result).toEqual({ |
| 146 |
days: '02', |
| 147 |
hours: '08', |
| 148 |
minutes: '15', |
| 149 |
seconds: '05', |
| 150 |
}); |
| 151 |
}); |
| 152 |
|
| 153 |
it('should calculate time left for future date', () => { |
| 154 |
// Set a date 1 day, 2 hours, 30 minutes, 45 seconds in the future |
| 155 |
const now = new Date(); |
| 156 |
const futureDate = new Date( |
| 157 |
now.getTime() + 1 * 24 * 60 * 60 * 1000 + 2 * 60 * 60 * 1000 + 30 * 60 * 1000 + 45 * 1000 |
| 158 |
); |
| 159 |
const result = calculateTimeLeft(futureDate.toISOString()); |
| 160 |
|
| 161 |
expect(result.days).toBe('01'); |
| 162 |
expect(result.hours).toBe('02'); |
| 163 |
expect(result.minutes).toBe('30'); |
| 164 |
// Seconds might vary slightly due to execution time |
| 165 |
expect(parseInt(result.seconds)).toBeGreaterThanOrEqual(44); |
| 166 |
expect(parseInt(result.seconds)).toBeLessThanOrEqual(46); |
| 167 |
}); |
| 168 |
|
| 169 |
it('should pad single digit values with zero', () => { |
| 170 |
const now = new Date(); |
| 171 |
const futureDate = new Date(now.getTime() + 5 * 1000); // 5 seconds from now |
| 172 |
const result = calculateTimeLeft(futureDate.toISOString()); |
| 173 |
|
| 174 |
expect(result.days).toBe('00'); |
| 175 |
expect(result.hours).toBe('00'); |
| 176 |
expect(result.minutes).toBe('00'); |
| 177 |
}); |
| 178 |
}); |
| 179 |
|
| 180 |
describe('getTimeUnits', () => { |
| 181 |
it('should return array of time units', () => { |
| 182 |
const timeLeft = { |
| 183 |
days: '02', |
| 184 |
hours: '12', |
| 185 |
minutes: '30', |
| 186 |
seconds: '45', |
| 187 |
}; |
| 188 |
const result = getTimeUnits(timeLeft); |
| 189 |
|
| 190 |
expect(result).toHaveLength(4); |
| 191 |
expect(result[0]).toEqual({ value: '02', label: 'DAYS' }); |
| 192 |
expect(result[1]).toEqual({ value: '12', label: 'HOURS' }); |
| 193 |
expect(result[2]).toEqual({ value: '30', label: 'MINUTES' }); |
| 194 |
expect(result[3]).toEqual({ value: '45', label: 'SECONDS' }); |
| 195 |
}); |
| 196 |
}); |
| 197 |
|
| 198 |
describe('buildDefaultCountdownState', () => { |
| 199 |
const mockDesign = { |
| 200 |
id: 'design1', |
| 201 |
hasSeparator: true, |
| 202 |
singleContainer: false, |
| 203 |
title: { |
| 204 |
text: 'Test Title', |
| 205 |
'font-family': 'Arial', |
| 206 |
'font-size': '14px', |
| 207 |
'font-weight': 600, |
| 208 |
'font-style': 'normal', |
| 209 |
color: '#FFFFFF', |
| 210 |
}, |
| 211 |
subtitle: { |
| 212 |
text: 'Test Subtitle', |
| 213 |
'font-family': 'Arial', |
| 214 |
'font-size': '12px', |
| 215 |
'font-weight': 400, |
| 216 |
'font-style': 'normal', |
| 217 |
color: '#CCCCCC', |
| 218 |
}, |
| 219 |
container: { |
| 220 |
background: '#FF0000', |
| 221 |
'border-radius': '6px', |
| 222 |
padding: '12px 16px', |
| 223 |
border: 0, |
| 224 |
'border-color': 'rgba(0, 0, 0, 0)', |
| 225 |
}, |
| 226 |
box: { |
| 227 |
background: '#FFFFFF', |
| 228 |
'border-radius': '2px', |
| 229 |
padding: '8px 12px', |
| 230 |
'min-width': '60px', |
| 231 |
}, |
| 232 |
number: { |
| 233 |
'font-family': 'Arial', |
| 234 |
'font-size': '20px', |
| 235 |
'font-weight': 700, |
| 236 |
color: '#FF0000', |
| 237 |
}, |
| 238 |
label: { |
| 239 |
'font-family': 'Arial', |
| 240 |
'font-size': '9px', |
| 241 |
'font-weight': 400, |
| 242 |
color: '#333333', |
| 243 |
}, |
| 244 |
separator: { |
| 245 |
color: '#FFFFFF', |
| 246 |
'font-size': '20px', |
| 247 |
'font-weight': 700, |
| 248 |
}, |
| 249 |
}; |
| 250 |
|
| 251 |
it('should build default state from design', () => { |
| 252 |
const result = buildDefaultCountdownState(mockDesign); |
| 253 |
|
| 254 |
expect(result.selected_design).toBe('design1'); |
| 255 |
expect(result.hasSeparator).toBe(true); |
| 256 |
expect(result.singleContainer).toBe(false); |
| 257 |
}); |
| 258 |
|
| 259 |
it('should include title properties', () => { |
| 260 |
const result = buildDefaultCountdownState(mockDesign); |
| 261 |
|
| 262 |
expect(result.title.text).toBe('Test Title'); |
| 263 |
expect(result.title.color).toBe('#FFFFFF'); |
| 264 |
expect(result.title['font-size']).toBe('14px'); |
| 265 |
}); |
| 266 |
|
| 267 |
it('should include container properties', () => { |
| 268 |
const result = buildDefaultCountdownState(mockDesign); |
| 269 |
|
| 270 |
expect(result.container.background).toBe('#FF0000'); |
| 271 |
expect(result.container.padding).toBe('12px 16px'); |
| 272 |
}); |
| 273 |
|
| 274 |
it('should include box properties with min-width', () => { |
| 275 |
const result = buildDefaultCountdownState(mockDesign); |
| 276 |
|
| 277 |
expect(result.box.background).toBe('#FFFFFF'); |
| 278 |
expect(result.box['min-width']).toBe('60px'); |
| 279 |
}); |
| 280 |
|
| 281 |
it('should include separator properties', () => { |
| 282 |
const result = buildDefaultCountdownState(mockDesign); |
| 283 |
|
| 284 |
expect(result.separator.color).toBe('#FFFFFF'); |
| 285 |
expect(result.separator['font-size']).toBe('20px'); |
| 286 |
}); |
| 287 |
}); |
| 288 |
}); |
| 289 |
|