senangwebs-epoch 1.1.3 → 1.1.4
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/README.md +13 -6
- package/SKILLS.md +81 -0
- package/dist/swe.js +1 -1
- package/package.json +2 -2
- package/src/js/swe.js +22 -23
- package/test/swe.test.js +95 -0
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
SenangWebs Epoch (SWE) is a lightweight JavaScript library for creating dynamic countdown timers and time displays. Whether you need to count down to a specific date, create a duration-based timer, or display the current time, SWE provides an elegant solution with minimal setup. The library supports flexible formatting, responsive design, and comprehensive event handling.
|
|
4
4
|
|
|
5
|
+
[](LICENSE.md)
|
|
6
|
+
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
9
|
- Multiple timer modes:
|
|
@@ -12,8 +14,9 @@ SenangWebs Epoch (SWE) is a lightweight JavaScript library for creating dynamic
|
|
|
12
14
|
- Customizable time unit formatting
|
|
13
15
|
- Responsive design out of the box
|
|
14
16
|
- Comprehensive event system
|
|
15
|
-
- Pause, resume, and reset functionality
|
|
16
|
-
-
|
|
17
|
+
- Pause, resume, and reset functionality
|
|
18
|
+
- Completed and expired countdowns stop cleanly and emit `swe:end` once
|
|
19
|
+
- No external dependencies
|
|
17
20
|
- Built-in default styling with CSS
|
|
18
21
|
- Works on all modern browsers
|
|
19
22
|
|
|
@@ -48,7 +51,7 @@ Include SenangWebs Epoch directly in your HTML file:
|
|
|
48
51
|
### Countdown to a specific date
|
|
49
52
|
|
|
50
53
|
```html
|
|
51
|
-
<div data-swe data-swe-countdown-end="
|
|
54
|
+
<div data-swe data-swe-countdown-end="2027-01-01T00:00:00">
|
|
52
55
|
<div data-swe-year data-swe-format="yyyy"></div>
|
|
53
56
|
<div data-swe-month data-swe-format="mm"></div>
|
|
54
57
|
<div data-swe-day data-swe-format="dd"></div>
|
|
@@ -119,7 +122,7 @@ The format string determines zero-padding based on its length:
|
|
|
119
122
|
const timer = new SWE(element, {
|
|
120
123
|
autostart: true,
|
|
121
124
|
duration: 60, // for countdown-duration mode
|
|
122
|
-
countdownEnd: '
|
|
125
|
+
countdownEnd: '2027-01-01T00:00:00', // ISO 8601, interpreted as local time
|
|
123
126
|
onTick: () => {
|
|
124
127
|
console.log('Timer ticked!');
|
|
125
128
|
},
|
|
@@ -166,14 +169,18 @@ timer.element.addEventListener('swe:end', (e) => {
|
|
|
166
169
|
});
|
|
167
170
|
```
|
|
168
171
|
|
|
169
|
-
Available events:
|
|
172
|
+
Available events:
|
|
170
173
|
- `swe:start`
|
|
171
174
|
- `swe:tick`
|
|
172
175
|
- `swe:pause`
|
|
173
176
|
- `swe:resume`
|
|
174
177
|
- `swe:reset`
|
|
175
178
|
- `swe:stop`
|
|
176
|
-
- `swe:end`
|
|
179
|
+
- `swe:end`
|
|
180
|
+
|
|
181
|
+
`swe:end` is emitted once when a countdown reaches zero. A countdown that is
|
|
182
|
+
already expired during initialization displays zero and does not leave a
|
|
183
|
+
background interval running.
|
|
177
184
|
|
|
178
185
|
## Styling
|
|
179
186
|
|
package/SKILLS.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: senangwebs-epoch
|
|
3
|
+
description: Dynamic countdown timers, duration timers, and current-time displays with flexible formatting and event callbacks.
|
|
4
|
+
version: 1.1.4
|
|
5
|
+
package: senangwebs-epoch
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# SenangWebs Epoch (SWE)
|
|
9
|
+
|
|
10
|
+
## Quick Reference
|
|
11
|
+
|
|
12
|
+
- **Purpose**: Countdown-to-date, countdown-duration, and current-time displays
|
|
13
|
+
- **Entry**: `dist/swe.js`
|
|
14
|
+
- **Dependencies**: none
|
|
15
|
+
- **Scripts**: `npm run build`, `npm run dev`, `npm run test`
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
Start in `C:\wamp64\www\sw-libraries\senangwebs-epoch`. Read `README.md`, `package.json`, and touched source files. Match existing patterns, CSS prefix `swe-`.
|
|
20
|
+
|
|
21
|
+
## HTML Data Attributes
|
|
22
|
+
|
|
23
|
+
### Container
|
|
24
|
+
| Attribute | Values |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `data-swe` | flag |
|
|
27
|
+
| `data-swe-countdown-end` | ISO 8601 date string |
|
|
28
|
+
| `data-swe-countdown-duration` | non-negative duration in seconds |
|
|
29
|
+
| `data-swe-current` | flag for current-time mode |
|
|
30
|
+
|
|
31
|
+
### Time unit display elements
|
|
32
|
+
| Attribute | Description |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `data-swe-year` | container for years |
|
|
35
|
+
| `data-swe-month` | container for months |
|
|
36
|
+
| `data-swe-day` | container for days |
|
|
37
|
+
| `data-swe-hour` | container for hours |
|
|
38
|
+
| `data-swe-minute` | container for minutes |
|
|
39
|
+
| `data-swe-second` | container for seconds |
|
|
40
|
+
| `data-swe-format` | padding token; its length sets the minimum width |
|
|
41
|
+
|
|
42
|
+
## JavaScript API
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
const timer = new SWE(element, {
|
|
46
|
+
autostart, countdownEnd, duration,
|
|
47
|
+
onTick, onEnd, onStart, onPause, onResume, onReset, onStop
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
timer.start()
|
|
51
|
+
timer.pause()
|
|
52
|
+
timer.resume()
|
|
53
|
+
timer.reset()
|
|
54
|
+
timer.stop()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### DOM Events
|
|
58
|
+
`swe:tick`, `swe:end`, `swe:start`, `swe:pause`, `swe:resume`, `swe:reset`, `swe:stop`
|
|
59
|
+
|
|
60
|
+
## Focus Areas
|
|
61
|
+
|
|
62
|
+
- Countdown accuracy: handle timezone differences, past dates, invalid dates
|
|
63
|
+
- Duration mode: decrementing timer with pause/resume/reset
|
|
64
|
+
- Clock mode: real-time display updating every second
|
|
65
|
+
- Format options: zero-padded vs natural number display
|
|
66
|
+
- Completed timer state: display zero, do not create or retain an interval, fire `onEnd`/`swe:end` once
|
|
67
|
+
|
|
68
|
+
## Implementation Guidance
|
|
69
|
+
|
|
70
|
+
- Preserve backward compatibility for all attributes and event names
|
|
71
|
+
- Handle edge cases: invalid dates should show error state, not crash
|
|
72
|
+
- Use ISO 8601 countdown dates such as `2027-01-01T00:00:00`
|
|
73
|
+
- Test across timezone changes (DST boundaries)
|
|
74
|
+
- Verify pause/resume doesn't drift accumulated time
|
|
75
|
+
|
|
76
|
+
## Validation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm run build
|
|
80
|
+
npm test
|
|
81
|
+
```
|
package/dist/swe.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SWE=e():t.SWE=e()}(this,(
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SWE=e():t.SWE=e()}(this,()=>(()=>{"use strict";var t={d:(e,n)=>{for(var i in n)t.o(n,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:n[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n<e;n++)i[n]=t[n];return i}function o(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,r(i.key),i)}}function r(t){var e=function(t){if("object"!=n(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var i=e.call(t,"string");if("object"!=n(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==n(e)?e:e+""}t.d(e,{default:()=>s});var a=function(){return t=function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.element=e,this.options={autostart:void 0===n.autostart||n.autostart,duration:n.duration,countdownEnd:n.countdownEnd,onTick:n.onTick,onEnd:n.onEnd,onStart:n.onStart,onPause:n.onPause,onResume:n.onResume,onReset:n.onReset,onStop:n.onStop},this.intervalId=null,this.isPaused=!1,this.startTime=null,this.pausedTimeRemaining=null,this.endTime=null,this.initialize()},(e=[{key:"initialize",value:function(){if(!(this.element&&this.element instanceof HTMLElement))throw new Error("SWE: Invalid element provided");if(this.mode=this.determineMode(),this.setupElements(),this.options.autostart)this.start();else if("countdown-duration"===this.mode&&this.options.duration)this.updateDisplay(1e3*this.options.duration);else if("countdown-end"===this.mode&&this.options.countdownEnd){var t=new Date(this.options.countdownEnd),e=new Date,n=t.getTime()-e.getTime();this.updateDisplay(n>0?n:0)}}},{key:"determineMode",value:function(){if(this.options.countdownEnd)return"countdown-end";if(this.options.duration)return"countdown-duration";if(this.element.hasAttribute("data-swe-countdown-end"))return"countdown-end";if(this.element.hasAttribute("data-swe-countdown-duration"))return"countdown-duration";if(this.element.hasAttribute("data-swe-current"))return"current";if(this.options.countdownEnd)return"countdown-end";throw new Error("SWE: Invalid mode - missing required configuration")}},{key:"setupElements",value:function(){this.elements={year:this.element.querySelector("[data-swe-year]"),month:this.element.querySelector("[data-swe-month]"),day:this.element.querySelector("[data-swe-day]"),hour:this.element.querySelector("[data-swe-hour]"),minute:this.element.querySelector("[data-swe-minute]"),second:this.element.querySelector("[data-swe-second]")}}},{key:"start",value:function(){if(!this.intervalId){switch(this.isPaused=!1,this.startTime=Date.now(),this.mode){case"countdown-end":this.startCountdownToDate();break;case"countdown-duration":this.startCountdownDuration();break;case"current":this.startCurrentTime()}this.dispatchEvent("start")}}},{key:"startCountdownToDate",value:function(){var t=new Date(this.options.countdownEnd||this.element.getAttribute("data-swe-countdown-end"));if(isNaN(t.getTime()))throw new Error("SWE: Invalid end date format");this.endTime=t.getTime(),this.updateTimer()}},{key:"startCountdownDuration",value:function(){var t=this.options.duration||parseInt(this.element.getAttribute("data-swe-countdown-duration"),10);if(isNaN(t)||t<0)throw new Error("SWE: Invalid duration");null!==this.pausedTimeRemaining?this.endTime=Date.now()+this.pausedTimeRemaining:this.endTime=Date.now()+1e3*t,this.updateTimer()}},{key:"updateTimer",value:function(){var t=this,e=function(){var e=Date.now(),n=t.endTime-e;return n<=0?(t.stop(),t.updateDisplay(0),t.dispatchEvent("end"),!1):(t.updateDisplay(n),t.dispatchEvent("tick"),!0)};e()&&(this.intervalId=setInterval(e,1e3))}},{key:"startCurrentTime",value:function(){var t=this,e=function(){var e=new Date;t.updateCurrentTimeDisplay(e),t.dispatchEvent("tick")};e(),this.intervalId=setInterval(e,1e3)}},{key:"updateDisplay",value:function(t){var e=this,n=this.calculateTimeUnits(t);Object.entries(this.elements).forEach(function(t){var o=function(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,o,r,a,s=[],u=!0,d=!1;try{if(r=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;u=!1}else for(;!(u=(i=r.call(n)).done)&&(s.push(i.value),s.length!==e);u=!0);}catch(t){d=!0,o=t}finally{try{if(!u&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(d)throw o}}return s}}(t,e)||function(t,e){if(t){if("string"==typeof t)return i(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}(t,2),r=o[0],a=o[1];a&&e.updateElement(a,n[r])})}},{key:"updateCurrentTimeDisplay",value:function(t){this.elements.hour&&this.updateElement(this.elements.hour,t.getHours()),this.elements.minute&&this.updateElement(this.elements.minute,t.getMinutes()),this.elements.second&&this.updateElement(this.elements.second,t.getSeconds())}},{key:"updateElement",value:function(t,e){var n=t.getAttribute("data-swe-format");t.textContent=this.formatValue(e,n)}},{key:"formatValue",value:function(t,e){return e?t.toString().padStart(e.length,"0"):t.toString()}},{key:"calculateTimeUnits",value:function(t){var e=Math.floor(t/1e3),n=Math.floor(e/60),i=Math.floor(n/60),o=(Math.floor(i/24),new Date),r=new Date(o.getTime()+t),a=r.getFullYear()-o.getFullYear(),s=r.getMonth()-o.getMonth(),u=r.getDate()-o.getDate();return u<0&&(s--,u+=new Date(r.getFullYear(),r.getMonth(),0).getDate()),s<0&&(a--,s+=12),{year:a,month:s,day:u,hour:i%24,minute:n%60,second:e%60}}},{key:"dispatchEvent",value:function(t){var e="on".concat(t.charAt(0).toUpperCase()+t.slice(1));"function"==typeof this.options[e]&&this.options[e].call(this);var n=new CustomEvent("swe:".concat(t),{bubbles:!0,detail:{instance:this}});this.element.dispatchEvent(n)}},{key:"pause",value:function(){this.intervalId&&!this.isPaused&&(clearInterval(this.intervalId),this.intervalId=null,this.isPaused=!0,this.pausedTimeRemaining=this.endTime-Date.now(),this.dispatchEvent("pause"))}},{key:"resume",value:function(){if(this.isPaused){switch(this.isPaused=!1,this.startTime=Date.now(),this.mode){case"countdown-end":this.startCountdownToDate();break;case"countdown-duration":this.startCountdownDuration();break;case"current":this.startCurrentTime()}this.dispatchEvent("resume")}}},{key:"reset",value:function(){if(this.stop(),this.pausedTimeRemaining=null,this.endTime=null,"countdown-end"===this.mode&&this.options.countdownEnd){var t=new Date(this.options.countdownEnd),e=new Date,n=t.getTime()-e.getTime();this.updateDisplay(n>0?n:0)}else"countdown-duration"===this.mode&&this.options.duration&&this.updateDisplay(1e3*this.options.duration);this.dispatchEvent("reset"),this.options.autostart&&this.start()}},{key:"stop",value:function(){var t=null!==this.intervalId;this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.isPaused=!1,t&&this.dispatchEvent("stop")}}])&&o(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,e}();document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll("[data-swe]").forEach(function(t){new a(t)})});const s=a;return"undefined"!=typeof window&&(window.SWE=a),e.default})());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "senangwebs-epoch",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Lightweight JavaScript library for creating dynamic countdown timers and time displays.",
|
|
5
5
|
"main": "dist/swe.js",
|
|
6
6
|
"module": "dist/swe.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "webpack --mode production",
|
|
12
12
|
"dev": "webpack --mode development --watch",
|
|
13
|
-
"test": "
|
|
13
|
+
"test": "node --test"
|
|
14
14
|
},
|
|
15
15
|
"keywords": ["countdown", "timer", "time", "epoch", "javascript", "date", "clock"],
|
|
16
16
|
"author": "a-hakim",
|
package/src/js/swe.js
CHANGED
|
@@ -140,28 +140,27 @@ class SWE {
|
|
|
140
140
|
this.updateTimer();
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
updateTimer() {
|
|
144
|
-
const update = () => {
|
|
145
|
-
const now = Date.now();
|
|
146
|
-
const remaining = this.endTime - now;
|
|
147
|
-
|
|
148
|
-
if (remaining <= 0) {
|
|
149
|
-
this.stop();
|
|
150
|
-
this.updateDisplay(0);
|
|
151
|
-
this.dispatchEvent('end');
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
this.updateDisplay(remaining);
|
|
156
|
-
this.dispatchEvent('tick');
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
update()
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
143
|
+
updateTimer() {
|
|
144
|
+
const update = () => {
|
|
145
|
+
const now = Date.now();
|
|
146
|
+
const remaining = this.endTime - now;
|
|
147
|
+
|
|
148
|
+
if (remaining <= 0) {
|
|
149
|
+
this.stop();
|
|
150
|
+
this.updateDisplay(0);
|
|
151
|
+
this.dispatchEvent('end');
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
this.updateDisplay(remaining);
|
|
156
|
+
this.dispatchEvent('tick');
|
|
157
|
+
return true;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
if (update()) {
|
|
161
|
+
this.intervalId = setInterval(update, 1000);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
165
164
|
|
|
166
165
|
startCurrentTime() {
|
|
167
166
|
const update = () => {
|
|
@@ -336,4 +335,4 @@ export default SWE;
|
|
|
336
335
|
|
|
337
336
|
if (typeof window !== 'undefined') {
|
|
338
337
|
window.SWE = SWE;
|
|
339
|
-
}
|
|
338
|
+
}
|
package/test/swe.test.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const test = require('node:test');
|
|
2
|
+
const assert = require('node:assert/strict');
|
|
3
|
+
|
|
4
|
+
class FakeHTMLElement {
|
|
5
|
+
constructor(attributes = {}) {
|
|
6
|
+
this.attributes = attributes;
|
|
7
|
+
this.events = [];
|
|
8
|
+
this.children = {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
hasAttribute(name) {
|
|
12
|
+
return Object.prototype.hasOwnProperty.call(this.attributes, name);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getAttribute(name) {
|
|
16
|
+
return this.attributes[name] ?? null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
querySelector(selector) {
|
|
20
|
+
return this.children[selector] ?? null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
dispatchEvent(event) {
|
|
24
|
+
this.events.push(event.type);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
global.HTMLElement = FakeHTMLElement;
|
|
29
|
+
global.CustomEvent = class CustomEvent {
|
|
30
|
+
constructor(type, options) {
|
|
31
|
+
this.type = type;
|
|
32
|
+
this.detail = options.detail;
|
|
33
|
+
this.bubbles = options.bubbles;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
global.document = {
|
|
37
|
+
addEventListener() {},
|
|
38
|
+
querySelectorAll() {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const SWE = require('../dist/swe.js');
|
|
44
|
+
|
|
45
|
+
test('expired countdown ends once without starting an interval', () => {
|
|
46
|
+
const element = new FakeHTMLElement({
|
|
47
|
+
'data-swe-countdown-end': '2000-01-01T00:00:00Z'
|
|
48
|
+
});
|
|
49
|
+
let endCount = 0;
|
|
50
|
+
let intervalCount = 0;
|
|
51
|
+
const originalSetInterval = global.setInterval;
|
|
52
|
+
|
|
53
|
+
global.setInterval = () => {
|
|
54
|
+
intervalCount += 1;
|
|
55
|
+
return 1;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const timer = new SWE(element, {
|
|
60
|
+
onEnd() {
|
|
61
|
+
endCount += 1;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
assert.equal(timer.intervalId, null);
|
|
66
|
+
assert.equal(intervalCount, 0);
|
|
67
|
+
assert.equal(endCount, 1);
|
|
68
|
+
assert.equal(element.events.filter(event => event === 'swe:end').length, 1);
|
|
69
|
+
} finally {
|
|
70
|
+
global.setInterval = originalSetInterval;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('zero-duration countdown ends without starting an interval', () => {
|
|
75
|
+
const element = new FakeHTMLElement({
|
|
76
|
+
'data-swe-countdown-duration': '0'
|
|
77
|
+
});
|
|
78
|
+
let intervalCount = 0;
|
|
79
|
+
const originalSetInterval = global.setInterval;
|
|
80
|
+
|
|
81
|
+
global.setInterval = () => {
|
|
82
|
+
intervalCount += 1;
|
|
83
|
+
return 1;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const timer = new SWE(element);
|
|
88
|
+
|
|
89
|
+
assert.equal(timer.intervalId, null);
|
|
90
|
+
assert.equal(intervalCount, 0);
|
|
91
|
+
assert.equal(element.events.filter(event => event === 'swe:end').length, 1);
|
|
92
|
+
} finally {
|
|
93
|
+
global.setInterval = originalSetInterval;
|
|
94
|
+
}
|
|
95
|
+
});
|