angular-datetime-input
Version:
A directive to add the behavior of datetime input on unsupported browsers
323 lines (250 loc) • 8.7 kB
JavaScript
/* eslint-env browser */
require("jsdom-global")();
var {describe, it, beforeEach, afterEach} = require("mocha"),
assert = require("assert");
// setup angular
require("angular/angular");
global.angular = window.angular;
// setup mocha for angular mock
window.mocha = true;
window.beforeEach = beforeEach;
window.afterEach = afterEach;
require("angular-mocks");
var {module, inject} = window;
require("../index");
var FORMATS = [
"yyyy-MM-dd HH:mm:ss",
"medium",
"short",
"fullDate",
"longDate",
"mediumDate",
"shortDate",
"mediumTime",
"shortTime",
",sss .sss",
"yyyy-MM-dd",
"Z"
];
function insertColon(timezone) {
if (timezone[3] == ":") {
return timezone;
}
return timezone.substr(0, 3) + ":" + timezone.substr(3, 2);
}
function randomTimezone(){
var offset = Math.floor(Math.random() * 24 * 60) - 12 * 60,
sign = offset >= 0 ? "+" : "-",
absOffset = Math.abs(offset),
hour = Math.floor(absOffset / 60),
min = absOffset % 60,
text = sign + padStart(hour, 2, "0") + padStart(min, 2, "0");
return {
time: offset * 60 * 1000,
text: text
};
}
function padStart(text, n, pad = " ") {
text = String(text);
if (n > text.length) {
text = pad
.repeat(Math.ceil((n - text.length) / pad.length))
.slice(0, n - text.length) + text;
}
return text;
}
describe("datetime service", () => {
var datetime, $date;
beforeEach(module("datetime"));
beforeEach(inject(function(_datetime_, $filter) {
datetime = _datetime_;
$date = $filter("date");
}));
FORMATS.forEach(format => {
it(`Format: ${format}`, () => {
var parser = datetime(format),
date = new Date,
text, model;
text = parser.setDate(date).getText();
assert.equal(text, $date(date, format));
model = parser.parse(text).getDate();
// 'yy' is ambigous in shortDate/short
if (format == "shortDate" || format == "short") {
assert.equal(model.getFullYear() % 100, date.getFullYear() % 100);
model.setFullYear(date.getFullYear());
}
assert.equal(model.getTime(), date.getTime());
});
});
it("duplicate tokens", () => {
var parser = datetime("yyyy-yyyy");
parser.parse("2000-2000");
assert.throws(
() => parser.parse("2000-2001"),
err => err.properText == "2001-2001"
);
assert.throws(
() => parser.parse("2001-2000"),
err => err.properText == "2001-2001"
);
});
it("tokens affect each others", () => {
var parser = datetime("fullDate");
parser.parse("Tuesday, May 5, 2015");
assert.throws(
() => parser.parse("Tuesday, May 1, 2015"),
err => err.properText == "Friday, May 1, 2015"
);
parser.parse("Friday, May 1, 2015");
assert.throws(
() => parser.parse("Friday, May 19, 2015"),
err => err.properText == "Tuesday, May 19, 2015"
);
parser.parse("Tuesday, May 19, 2015");
assert.equal(parser.getText(), "Tuesday, May 19, 2015");
assert.throws(
() => parser.parse("Monday, May 19, 2015"),
err => err.properText == "Monday, May 18, 2015"
);
parser.parse("Monday, May 18, 2015");
parser.parse("Sunday, May 17, 2015");
parser.parse("Sunday, May 17, 2015");
});
it("31 date overflow", () => {
var parser = datetime("medium");
parser.parse("Mar 31, 2016 6:19:20 PM");
parser.parse("Apr 1, 2016 10:42:20 AM");
});
it("initial value", () => {
var parser = datetime("fullDate"),
date = new Date;
assert.ok(date.getTime() - parser.getDate().getTime() < 10);
assert.equal(parser.getText(), $date(parser.getDate(), "fullDate"));
});
it("timezone: utc time + offset should always equal on same date", () => {
var parser = datetime("medium"),
r1 = randomTimezone(),
r2 = randomTimezone(),
text = parser.getText(),
t1, t2;
parser.setTimezone(r1.text);
parser.parse(text);
t1 = parser.getDate().getTime();
parser.setTimezone(r2.text);
parser.parse(text);
t2 = parser.getDate().getTime();
assert.equal(t1 + r1.time, t2 + r2.time);
});
it("ZZ token", () => {
var parser = datetime("ZZ");
assert.equal(parser.getText(), insertColon($date(parser.getDate(), "Z")));
});
it("Overflowed day with empty month", ()=> {
var parser = datetime("dd.MM.yyyy");
parser.parse("01.06.2017");
assert.throws(
() => parser.parse("31.(month).(year)"),
err => err.code == "NOT_INIT"
);
});
it("Overflowed day with empty month (add)", ()=> {
var parser = datetime("dd.MM.yyyy");
parser.parse("30.06.2017");
parser.tp.nodes[0].add(1);
assert.equal(parser.getText(), "01.07.2017");
parser.parse("30.06.2017");
parser.tp.unset();
parser.tp.nodes[0].add(1);
assert.equal(parser.getText(), "31.(month).(year)");
});
});
describe("datetime directive", function(){
var $rootScope, $date, $compile;
beforeEach(module("datetime"));
beforeEach(inject(function(_$compile_, _$rootScope_, $filter){
$rootScope = _$rootScope_;
$date = $filter("date");
$compile = _$compile_;
}));
FORMATS.forEach(format => {
it(`Format: ${format}`, function(){
$rootScope.format = format;
$rootScope.date = new Date;
var element = $compile("<input type='text' datetime='{{format}}' ng-model='date'>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), $date($rootScope.date, format));
});
});
it("timezone and utc", function(){
$rootScope.date = new Date;
var element = $compile("<input type='text' datetime='Z' ng-model='date' datetime-utc>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), "+0000");
});
it("datetime-timezone and custom timezone", function(){
$rootScope.date = new Date;
$rootScope.timezone = "+0500";
var element = $compile("<input type='text' datetime='Z' ng-model='date' datetime-timezone='timezone'>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), "+0500");
});
it("datetime-timezone and utc format with colon", function(){
$rootScope.date = new Date;
$rootScope.timezone = "+07:00";
var element = $compile("<input type='text' datetime='Z' ng-model='date' datetime-timezone='timezone'>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), "+0700");
});
it("dynamic datetime-timezone", function(){
$rootScope.date = new Date;
$rootScope.timezone = "+0500";
var element = $compile("<input type='text' datetime='Z' ng-model='date' datetime-timezone='timezone'>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), "+0500");
$rootScope.timezone = "+0800";
$rootScope.$digest();
assert.equal(element.val(), "+0800");
});
it("static datetime-timezone", function(){
$rootScope.date = new Date;
var element = $compile("<input type='text' datetime='Z' ng-model='date' datetime-timezone='+0500'>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), "+0500");
});
it("dynamic datetime-utc", function(){
var date = $rootScope.date = new Date;
$rootScope.utc = true;
var element = $compile("<input type='text' datetime='Z' ng-model='date' datetime-utc='utc'>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), "+0000");
$rootScope.utc = false;
$rootScope.$digest();
assert.equal(element.val(), $date(date, "Z"));
});
it("datetime-model", function(){
var date = new Date;
$rootScope.dateString = $date(date, "yyyy-MM-dd HH:mm:ss");
var element = $compile("<input type='text' datetime='medium' datetime-model='yyyy-MM-dd HH:mm:ss' ng-model='dateString'>")($rootScope);
$rootScope.$digest();
assert.equal(element.val(), $date(date, "medium"));
});
it("min & max", function(){
$rootScope.min = "2000-01-01";
$rootScope.max = "2020-01-01";
var element = $compile("<input type='text' datetime='yyyy-MM-dd HH:mm:ss' ng-model='date' min='{{min}}' max='{{max}}'>")($rootScope);
$rootScope.$digest();
element.val("1999-01-01 00:00:00").triggerHandler("input");
$rootScope.$digest();
assert.equal(element.hasClass("ng-invalid-min"), true);
element.val("2016-06-18 22:59:00").triggerHandler("input");
$rootScope.$digest();
assert.equal(element.hasClass("ng-invalid"), false);
element.val("2021-01-01 00:00:00").triggerHandler("input");
$rootScope.$digest();
assert.equal(element.hasClass("ng-invalid-max"), true);
$rootScope.min = null;
$rootScope.max = null;
$rootScope.$digest();
assert.equal(element.hasClass("ng-invalid"), false);
});
});