Commit d705108b by Torkel Ödegaard

feat(timepicker2): added date math tests

parent 3912eb7b
...@@ -66,6 +66,6 @@ ...@@ -66,6 +66,6 @@
"grunt-sync": "^0.4.1", "grunt-sync": "^0.4.1",
"karma-sinon": "^1.0.3", "karma-sinon": "^1.0.3",
"lodash": "^2.4.1", "lodash": "^2.4.1",
"sinon": "1.10.3" "sinon": "1.16.1"
} }
} }
...@@ -11,7 +11,7 @@ var unitsDesc = unitsAsc.reverse(); ...@@ -11,7 +11,7 @@ var unitsDesc = unitsAsc.reverse();
export class DateMath { export class DateMath {
static parse(text, roundUp) { static parse(text, roundUp?) {
if (!text) { return undefined; } if (!text) { return undefined; }
if (moment.isMoment(text)) { return text; } if (moment.isMoment(text)) { return text; }
if (_.isDate(text)) { return moment(text); } if (_.isDate(text)) { return moment(text); }
...@@ -44,7 +44,7 @@ export class DateMath { ...@@ -44,7 +44,7 @@ export class DateMath {
return DateMath.parseDateMath(mathString, time, roundUp); return DateMath.parseDateMath(mathString, time, roundUp);
} }
static parseDateMath(mathString, time, roundUp) { static parseDateMath(mathString, time, roundUp?) {
var dateTime = time; var dateTime = time;
var i = 0; var i = 0;
var len = mathString.length; var len = mathString.length;
......
///<reference path="../../app/headers/common.d.ts" />
var _global = <any>(window);
var beforeEach = _global.beforeEach;
var describe = _global.describe;
var it = _global.it;
var sinon = _global.sinon;
var expect = _global.expect;
export {
beforeEach,
describe,
it,
sinon,
expect
}
import {DateMath} from 'app/core/utils/datemath' import {DateMath} from 'app/core/utils/datemath'
import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'
declare var describe: any; import _ = require('lodash')
declare var expect: any; import moment = require('moment')
declare var it: any;
describe("test", () => { describe.only("DateMath", () => {
var spans = ['s', 'm', 'h', 'd', 'w', 'M', 'y'];
var anchor = '2014-01-01T06:06:06.666Z';
var unix = moment(anchor).valueOf();
var format = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
var clock;
it("hello", () => { describe('errors', () => {
expect(true).to.be(true); it('should return undefined if passed something falsy', () => {
expect(DateMath.parse(false)).to.be(undefined);
}); });
it('should return undefined if I pass an operator besides [+-/]', () => {
expect(DateMath.parse('now&1d')).to.be(undefined);
});
it('should return undefined if I pass a unit besides' + spans.toString(), () => {
expect(DateMath.parse('now+5f')).to.be(undefined);
});
it('should return undefined if rounding unit is not 1', () => {
expect(DateMath.parse('now/2y')).to.be(undefined);
expect(DateMath.parse('now/0.5y')).to.be(undefined);
});
it('should not go into an infinite loop when missing a unit', () => {
expect(DateMath.parse('now-0')).to.be(undefined);
expect(DateMath.parse('now-00')).to.be(undefined);
});
});
it("now/d should set to start of current day", () => {
var expected = new Date();
expected.setHours(0);
expected.setMinutes(0);
expected.setSeconds(0);
expected.setMilliseconds(0);
var startOfDay = DateMath.parse('now/d', false).valueOf()
expect(startOfDay).to.be(expected.getTime());
});
describe('subtraction', () => {
var now;
var anchored;
beforeEach(() => {
clock = sinon.useFakeTimers(unix);
now = moment();
anchored = moment(anchor);
});
_.each(spans, (span) => {
var nowEx = 'now-5' + span;
var thenEx = anchor + '||-5' + span;
it('should return 5' + span + ' ago', () => {
expect(DateMath.parse(nowEx).format(format)).to.eql(now.subtract(5, span).format(format));
});
it('should return 5' + span + ' before ' + anchor, () => {
expect(DateMath.parse(thenEx).format(format)).to.eql(anchored.subtract(5, span).format(format));
});
});
});
describe('rounding', () => {
var now;
var anchored;
beforeEach(() => {
clock = sinon.useFakeTimers(unix);
now = moment();
anchored = moment(anchor);
});
_.each(spans, (span) => {
it('should round now to the beginning of the ' + span, function () {
expect(DateMath.parse('now/' + span).format(format)).to.eql(now.startOf(span).format(format));
});
it('should round now to the end of the ' + span, function () {
expect(DateMath.parse('now/' + span, true).format(format)).to.eql(now.endOf(span).format(format));
});
});
});
}); });
export = {}; export = {};
......
...@@ -103,79 +103,30 @@ function file2moduleName(filePath) { ...@@ -103,79 +103,30 @@ function file2moduleName(filePath) {
} }
require([ require([
'lodash',
'angular', 'angular',
'angularMocks', 'angularMocks',
'app/app', 'app/app',
], function(angular) { ], function(_, angular) {
'use strict'; 'use strict';
var specs = []; var specs = [];
for (var file in window.__karma__.files) { for (var file in window.__karma__.files) {
if (/base\/test\/specs.*/.test(file)) { if (/base\/test\/specs.*/.test(file)) {
console.log(file);
file = file2moduleName(file); file = file2moduleName(file);
console.log(file);
specs.push(file); specs.push(file);
//file = file.replace(/^\/base\/test/, '');
//specs.push(file);
//window.tests.push();
} }
} }
require(specs, function() {
window.__karma__.start();
});
angular.module('grafana', ['ngRoute']); angular.module('grafana', ['ngRoute']);
angular.module('grafana.services', ['ngRoute', '$strap.directives']); angular.module('grafana.services', ['ngRoute', '$strap.directives']);
angular.module('grafana.panels', []); angular.module('grafana.panels', []);
angular.module('grafana.filters', []); angular.module('grafana.filters', []);
angular.module('grafana.routes', ['ngRoute']); angular.module('grafana.routes', ['ngRoute']);
// var specs = [ require(specs, function() {
// 'specs/lexer-specs', window.__karma__.start();
// 'specs/parser-specs', });
// 'specs/gfunc-specs',
// 'specs/timeSeries-specs',
// 'specs/row-ctrl-specs',
// 'specs/graphiteTargetCtrl-specs',
// 'specs/graphiteDatasource-specs',
// 'specs/influxSeries-specs',
// 'specs/influxSeries08-specs',
// 'specs/influxQueryBuilder-specs',
// 'specs/influx09-querybuilder-specs',
// // 'specs/influxdb-datasource-specs',
// 'specs/influxdbQueryCtrl-specs',
// // 'specs/kairosdb-datasource-specs',
// 'specs/graph-ctrl-specs',
// 'specs/graph-specs',
// 'specs/graph-tooltip-specs',
// 'specs/seriesOverridesCtrl-specs',
// 'specs/shareModalCtrl-specs',
// 'specs/timeSrv-specs',
// 'specs/panelSrv-specs',
// 'specs/templateSrv-specs',
// 'specs/templateValuesSrv-specs',
// 'specs/kbn-format-specs',
// 'specs/dashboardSrv-specs',
// 'specs/dashboardViewStateSrv-specs',
// 'specs/singlestat-specs',
// 'specs/dynamicDashboardSrv-specs',
// 'specs/unsavedChangesSrv-specs',
// 'specs/value_select_dropdown_specs',
// 'specs/opentsdbDatasource-specs',
// 'specs/cloudwatch-datasource-specs',
// 'specs/elasticsearch-specs',
// 'specs/elasticsearch-querybuilder-specs',
// 'specs/elasticsearch-queryctrl-specs',
// 'specs/elasticsearch-indexPattern-specs',
// 'specs/elasticsearch-response-specs',
// 'specs/core/utils/datemath_specs',
// ];
//
// var pluginSpecs = (config.plugins.specs || []).map(function (spec) {
// return '../plugins/' + spec;
// });
}); });
{ {
"compilerOptions": { "compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true, "sourceMap": true,
"declaration": true, "declaration": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": true,
"outDir": "public_gen/app", "outDir": "public_gen/app",
"target": "ES5", "target": "ES5",
"rootDir": "public/app", "rootDir": "public/app",
"sourceRoot": "public/app",
"module": "amd", "module": "amd",
"noEmitOnError": true "noEmitOnError": true
}, },
"fileGlobs": [ "files": [
"./public/app/**/*.ts", "public/app/components/panelmeta.ts",
"!./node_modules/**", "public/app/controllers/signupCtrl.ts",
"!./public_gen/**", "public/app/core/core.ts",
"public/app/core/core_module.ts",
"public/app/core/directives/array_join.ts",
"public/app/core/directives/give_focus.ts",
"public/app/core/filters/filters.ts",
"public/app/core/routes/bundle_loader.ts",
"public/app/core/utils/datemath.ts",
"public/app/features/dashboard/timepicker/timepicker.ts",
"public/app/features/dashboard/timepicker/timerange.ts",
"public/app/headers/angularjs/angularjs.d.ts",
"public/app/headers/common.d.ts",
"public/app/headers/jquery/jquery.d.ts",
"public/app/headers/lodash/lodash.d.ts",
"public/app/headers/moment/moment-node.d.ts",
"public/app/headers/moment/moment.d.ts",
"public/app/headers/require/require.d.ts"
] ]
} }
\ No newline at end of file
{
"version": "v4",
"repo": "angular/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"es6-promise/es6-promise.d.ts": {
"commit": "be0b6b394f77a59e192ad7cfec18078706e44db5"
},
"mocha/mocha.d.ts": {
"commit": "055b3172e8eb374a75826710c4d08677872620d3"
},
"node/node.d.ts": {
"commit": "51738fdf1643d269067861b405e87503b7479236"
},
"zone/zone.d.ts": {
"commit": "055b3172e8eb374a75826710c4d08677872620d3"
}
}
}
// Type definitions for es6-promise
// Project: https://github.com/jakearchibald/ES6-Promise
// Definitions by: François de Campredon <https://github.com/fdecampredon/>, vvakame <https://github.com/vvakame>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
interface Thenable<R> {
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error: any) => U | Thenable<U>): Thenable<U>;
}
declare class Promise<R> implements Thenable<R> {
/**
* If you call resolve in the body of the callback passed to the constructor,
* your promise is fulfilled with result object passed to resolve.
* If you call reject your promise is rejected with the object passed to resolve.
* For consistency and debugging (eg stack traces), obj should be an instanceof Error.
* Any errors thrown in the constructor callback will be implicitly passed to reject().
*/
constructor(callback: (resolve : (value?: R | Thenable<R>) => void, reject: (error?: any) => void) => void);
/**
* onFulfilled is called when/if "promise" resolves. onRejected is called when/if "promise" rejects.
* Both are optional, if either/both are omitted the next onFulfilled/onRejected in the chain is called.
* Both callbacks have a single parameter , the fulfillment value or rejection reason.
* "then" returns a new promise equivalent to the value you return from onFulfilled/onRejected after being passed through Promise.resolve.
* If an error is thrown in the callback, the returned promise rejects with that error.
*
* @param onFulfilled called when/if "promise" resolves
* @param onRejected called when/if "promise" rejects
*/
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error: any) => U | Thenable<U>): Promise<U>;
/**
* Sugar for promise.then(undefined, onRejected)
*
* @param onRejected called when/if "promise" rejects
*/
catch<U>(onRejected?: (error: any) => U | Thenable<U>): Promise<U>;
}
declare module Promise {
/**
* Make a new promise from the thenable.
* A thenable is promise-like in as far as it has a "then" method.
*/
function resolve<R>(value?: R | Thenable<R>): Promise<R>;
/**
* Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error
*/
function reject(error: any): Promise<any>;
/**
* Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects.
* the array passed to all can be a mixture of promise-like objects and other objects.
* The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value.
*/
function all<R>(promises: (R | Thenable<R>)[]): Promise<R[]>;
/**
* Make a Promise that fulfills when any item fulfills, and rejects if any item rejects.
*/
function race<R>(promises: (R | Thenable<R>)[]): Promise<R>;
}
declare module 'es6-promise' {
var foo: typeof Promise; // Temp variable to reference Promise in local context
module rsvp {
export var Promise: typeof foo;
}
export = rsvp;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
// Type definitions for mocha 2.2.5
// Project: http://mochajs.org/
// Definitions by: Kazi Manzur Rashid <https://github.com/kazimanzurrashid/>, otiai10 <https://github.com/otiai10>, jt000 <https://github.com/jt000>, Vadim Macagon <https://github.com/enlight>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
interface MochaSetupOptions {
//milliseconds to wait before considering a test slow
slow?: number;
// timeout in milliseconds
timeout?: number;
// ui name "bdd", "tdd", "exports" etc
ui?: string;
//array of accepted globals
globals?: any[];
// reporter instance (function or string), defaults to `mocha.reporters.Spec`
reporter?: any;
// bail on the first test failure
bail?: boolean;
// ignore global leaks
ignoreLeaks?: boolean;
// grep string or regexp to filter tests with
grep?: any;
}
interface MochaDone {
(error?: Error): void;
}
declare var mocha: Mocha;
declare var describe: Mocha.IContextDefinition;
declare var xdescribe: Mocha.IContextDefinition;
// alias for `describe`
declare var context: Mocha.IContextDefinition;
// alias for `describe`
declare var suite: Mocha.IContextDefinition;
declare var it: Mocha.ITestDefinition;
declare var xit: Mocha.ITestDefinition;
// alias for `it`
declare var test: Mocha.ITestDefinition;
declare function before(action: () => void): void;
declare function before(action: (done: MochaDone) => void): void;
declare function setup(action: () => void): void;
declare function setup(action: (done: MochaDone) => void): void;
declare function after(action: () => void): void;
declare function after(action: (done: MochaDone) => void): void;
declare function teardown(action: () => void): void;
declare function teardown(action: (done: MochaDone) => void): void;
declare function beforeEach(action: () => void): void;
declare function beforeEach(action: (done: MochaDone) => void): void;
declare function suiteSetup(action: () => void): void;
declare function suiteSetup(action: (done: MochaDone) => void): void;
declare function afterEach(action: () => void): void;
declare function afterEach(action: (done: MochaDone) => void): void;
declare function suiteTeardown(action: () => void): void;
declare function suiteTeardown(action: (done: MochaDone) => void): void;
declare class Mocha {
constructor(options?: {
grep?: RegExp;
ui?: string;
reporter?: string;
timeout?: number;
bail?: boolean;
});
/** Setup mocha with the given options. */
setup(options: MochaSetupOptions): Mocha;
bail(value?: boolean): Mocha;
addFile(file: string): Mocha;
/** Sets reporter by name, defaults to "spec". */
reporter(name: string): Mocha;
/** Sets reporter constructor, defaults to mocha.reporters.Spec. */
reporter(reporter: (runner: Mocha.IRunner, options: any) => any): Mocha;
ui(value: string): Mocha;
grep(value: string): Mocha;
grep(value: RegExp): Mocha;
invert(): Mocha;
ignoreLeaks(value: boolean): Mocha;
checkLeaks(): Mocha;
/** Enables growl support. */
growl(): Mocha;
globals(value: string): Mocha;
globals(values: string[]): Mocha;
useColors(value: boolean): Mocha;
useInlineDiffs(value: boolean): Mocha;
timeout(value: number): Mocha;
slow(value: number): Mocha;
enableTimeouts(value: boolean): Mocha;
asyncOnly(value: boolean): Mocha;
noHighlighting(value: boolean): Mocha;
/** Runs tests and invokes `onComplete()` when finished. */
run(onComplete?: (failures: number) => void): Mocha.IRunner;
}
// merge the Mocha class declaration with a module
declare module Mocha {
/** Partial interface for Mocha's `Runnable` class. */
interface IRunnable {
title: string;
fn: Function;
async: boolean;
sync: boolean;
timedOut: boolean;
}
/** Partial interface for Mocha's `Suite` class. */
interface ISuite {
parent: ISuite;
title: string;
fullTitle(): string;
}
/** Partial interface for Mocha's `Test` class. */
interface ITest extends IRunnable {
parent: ISuite;
pending: boolean;
fullTitle(): string;
}
/** Partial interface for Mocha's `Runner` class. */
interface IRunner {}
interface IContextDefinition {
(description: string, spec: () => void): ISuite;
only(description: string, spec: () => void): ISuite;
skip(description: string, spec: () => void): void;
timeout(ms: number): void;
}
interface ITestDefinition {
(expectation: string, assertion?: () => void): ITest;
(expectation: string, assertion?: (done: MochaDone) => void): ITest;
only(expectation: string, assertion?: () => void): ITest;
only(expectation: string, assertion?: (done: MochaDone) => void): ITest;
skip(expectation: string, assertion?: () => void): void;
skip(expectation: string, assertion?: (done: MochaDone) => void): void;
timeout(ms: number): void;
}
export module reporters {
export class Base {
stats: {
suites: number;
tests: number;
passes: number;
pending: number;
failures: number;
};
constructor(runner: IRunner);
}
export class Doc extends Base {}
export class Dot extends Base {}
export class HTML extends Base {}
export class HTMLCov extends Base {}
export class JSON extends Base {}
export class JSONCov extends Base {}
export class JSONStream extends Base {}
export class Landing extends Base {}
export class List extends Base {}
export class Markdown extends Base {}
export class Min extends Base {}
export class Nyan extends Base {}
export class Progress extends Base {
/**
* @param options.open String used to indicate the start of the progress bar.
* @param options.complete String used to indicate a complete test on the progress bar.
* @param options.incomplete String used to indicate an incomplete test on the progress bar.
* @param options.close String used to indicate the end of the progress bar.
*/
constructor(runner: IRunner, options?: {
open?: string;
complete?: string;
incomplete?: string;
close?: string;
});
}
export class Spec extends Base {}
export class TAP extends Base {}
export class XUnit extends Base {
constructor(runner: IRunner, options?: any);
}
}
}
declare module "mocha" {
export = Mocha;
}
/// <reference path="es6-promise/es6-promise.d.ts" />
/// <reference path="mocha/mocha.d.ts" />
/// <reference path="node/node.d.ts" />
/// <reference path="zone/zone.d.ts" />
declare module Zone {
export class Stacktrace {
constructor(e: Error);
get(): string;
}
}
declare class Zone {
constructor(parentZone: Zone, data: any);
fork(locals: any): Zone;
bind(fn, skipEnqueue): void;
bindOnce(fn): any;
run(fn, applyTo?, applyWith?): void;
beforeTask(): void;
onZoneCreated(): void;
afterTask(): void;
enqueueTask(): void;
dequeueTask(): void;
static patchSetClearFn(obj, fnNames): string;
static patchPrototype(obj, fnNames): any;
static bindArguments(args: any[]): any;
static bindArgumentsOnce(args: any[]): any;
static patchableFn(obj, fnNames): any
static patchProperty(obj, prop): void;
static patchProperties(obj, properties): void;
static patchEventTargetMethods(obj): void;
static patch(): void;
static canPatchViaPropertyDescriptor(): boolean;
static patchViaPropertyDescriptor(): void;
static patchViaCapturingAllTheEvents(): void;
static patchWebSocket(): void;
static patchClass(className: string): void;
static patchMutationObserverClass(className: string): void;
static patchDefineProperty(): void;
static patchRegisterElement(): void;
static eventNames: string;
static onEventNames: string;
static init(): void;
static exceptZone: {
boringZone: Zone;
interestingZone: Zone,
beforeTask: () => void;
afterTask: () => void;
fork: (ops: any) => Zone;
};
static longStackTraceZone: {
getLongStacktrace(exception: any): string;
stackFramesFilter(line: string): boolean;
onError(exception): void;
fork(locals): Zone;
};
static getStacktrace(): Zone.Stacktrace;
static countingZone: {
'+enqueueTask': () => void;
'-dequeueTask': () => void;
'+afterTask': () => void;
counter: () => void;
data: {
count: number;
flushed: boolean;
};
onFlush: () => void;
};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment