diff --git a/packages/elastic-datemath/__tests__/index.js b/packages/elastic-datemath/index.test.js
similarity index 69%
rename from packages/elastic-datemath/__tests__/index.js
rename to packages/elastic-datemath/index.test.js
index 1a61021b48a6e..a6a576dd713a9 100644
--- a/packages/elastic-datemath/__tests__/index.js
+++ b/packages/elastic-datemath/index.test.js
@@ -17,22 +17,21 @@
  * under the License.
  */
 
-const dateMath = require('../index');
+const dateMath = require('./index');
 const moment = require('moment');
-const sinon = require('sinon');
-const expect = require('@kbn/expect');
 
 /**
- * Require a new instance of the moment library, bypassing the require cache.
+ * Require a new instance of the moment library, bypassing the require cache
+ * by using jest.resetModules().
  * This is needed, since we are trying to test whether or not this library works
  * when passing in a different configured moment instance. If we would change
  * the locales on the imported moment, it would automatically apply
  * to the source code, even without passing it in to the method, since they share
  * the same global state. This method avoids this, by loading a separate instance
- * of moment, by deleting the require cache and require the library again.
+ * of moment, by resetting the jest require modules cache and require the library again.
  */
 function momentClone() {
-  delete require.cache[require.resolve('moment')];
+  jest.resetModules();
   return require('moment');
 }
 
@@ -43,44 +42,43 @@ describe('dateMath', function () {
   const anchoredDate = new Date(Date.parse(anchor));
   const unix = moment(anchor).valueOf();
   const format = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
-  let clock;
 
   describe('errors', function () {
     it('should return undefined if passed something falsy', function () {
-      expect(dateMath.parse()).to.be(undefined);
+      expect(dateMath.parse()).toBeUndefined();
     });
 
     it('should return undefined if I pass an operator besides [+-/]', function () {
-      expect(dateMath.parse('now&1d')).to.be(undefined);
+      expect(dateMath.parse('now&1d')).toBeUndefined();
     });
 
     it('should return undefined if I pass a unit besides' + spans.toString(), function () {
-      expect(dateMath.parse('now+5f')).to.be(undefined);
+      expect(dateMath.parse('now+5f')).toBeUndefined();
     });
 
     it('should return undefined if rounding unit is not 1', function () {
-      expect(dateMath.parse('now/2y')).to.be(undefined);
-      expect(dateMath.parse('now/0.5y')).to.be(undefined);
+      expect(dateMath.parse('now/2y')).toBeUndefined();
+      expect(dateMath.parse('now/0.5y')).toBeUndefined();
     });
 
     it('should not go into an infinite loop when missing a unit', function () {
-      expect(dateMath.parse('now-0')).to.be(undefined);
-      expect(dateMath.parse('now-00')).to.be(undefined);
-      expect(dateMath.parse('now-000')).to.be(undefined);
+      expect(dateMath.parse('now-0')).toBeUndefined();
+      expect(dateMath.parse('now-00')).toBeUndefined();
+      expect(dateMath.parse('now-000')).toBeUndefined();
     });
 
     describe('forceNow', function () {
       it('should throw an Error if passed a string', function () {
         const fn = () => dateMath.parse('now', { forceNow: '2000-01-01T00:00:00.000Z' });
-        expect(fn).to.throwError();
+        expect(fn).toThrowError();
       });
 
       it('should throw an Error if passed a moment', function () {
-        expect(() => dateMath.parse('now', { forceNow: moment() })).to.throwError();
+        expect(() => dateMath.parse('now', { forceNow: moment() })).toThrowError();
       });
 
       it('should throw an Error if passed an invalid date', function () {
-        expect(() => dateMath.parse('now', { forceNow: new Date('foobar') })).to.throwError();
+        expect(() => dateMath.parse('now', { forceNow: new Date('foobar') })).toThrowError();
       });
     });
   });
@@ -92,7 +90,8 @@ describe('dateMath', function () {
     let now;
 
     beforeEach(function () {
-      clock = sinon.useFakeTimers(unix);
+      jest.useFakeTimers('modern');
+      jest.setSystemTime(unix);
       now = moment();
       mmnt = moment(anchor);
       date = mmnt.toDate();
@@ -100,27 +99,27 @@ describe('dateMath', function () {
     });
 
     afterEach(function () {
-      clock.restore();
+      jest.useRealTimers();
     });
 
     it('should return the same moment if passed a moment', function () {
-      expect(dateMath.parse(mmnt)).to.eql(mmnt);
+      expect(dateMath.parse(mmnt)).toEqual(mmnt);
     });
 
     it('should return a moment if passed a date', function () {
-      expect(dateMath.parse(date).format(format)).to.eql(mmnt.format(format));
+      expect(dateMath.parse(date).format(format)).toEqual(mmnt.format(format));
     });
 
     it('should return a moment if passed an ISO8601 string', function () {
-      expect(dateMath.parse(string).format(format)).to.eql(mmnt.format(format));
+      expect(dateMath.parse(string).format(format)).toEqual(mmnt.format(format));
     });
 
     it('should return the current time when parsing now', function () {
-      expect(dateMath.parse('now').format(format)).to.eql(now.format(format));
+      expect(dateMath.parse('now').format(format)).toEqual(now.format(format));
     });
 
     it('should use the forceNow parameter when parsing now', function () {
-      expect(dateMath.parse('now', { forceNow: anchoredDate }).valueOf()).to.eql(unix);
+      expect(dateMath.parse('now', { forceNow: anchoredDate }).valueOf()).toEqual(unix);
     });
   });
 
@@ -129,13 +128,14 @@ describe('dateMath', function () {
     let anchored;
 
     beforeEach(function () {
-      clock = sinon.useFakeTimers(unix);
+      jest.useFakeTimers('modern');
+      jest.setSystemTime(unix);
       now = moment();
       anchored = moment(anchor);
     });
 
     afterEach(function () {
-      clock.restore();
+      jest.useRealTimers();
     });
 
     [5, 12, 247].forEach((len) => {
@@ -145,17 +145,17 @@ describe('dateMath', function () {
 
         it('should return ' + len + span + ' ago', function () {
           const parsed = dateMath.parse(nowEx).format(format);
-          expect(parsed).to.eql(now.subtract(len, span).format(format));
+          expect(parsed).toEqual(now.subtract(len, span).format(format));
         });
 
         it('should return ' + len + span + ' before ' + anchor, function () {
           const parsed = dateMath.parse(thenEx).format(format);
-          expect(parsed).to.eql(anchored.subtract(len, span).format(format));
+          expect(parsed).toEqual(anchored.subtract(len, span).format(format));
         });
 
         it('should return ' + len + span + ' before forceNow', function () {
           const parsed = dateMath.parse(nowEx, { forceNow: anchoredDate }).valueOf();
-          expect(parsed).to.eql(anchored.subtract(len, span).valueOf());
+          expect(parsed).toEqual(anchored.subtract(len, span).valueOf());
         });
       });
     });
@@ -166,13 +166,14 @@ describe('dateMath', function () {
     let anchored;
 
     beforeEach(function () {
-      clock = sinon.useFakeTimers(unix);
+      jest.useFakeTimers('modern');
+      jest.setSystemTime(unix);
       now = moment();
       anchored = moment(anchor);
     });
 
     afterEach(function () {
-      clock.restore();
+      jest.useRealTimers();
     });
 
     [5, 12, 247].forEach((len) => {
@@ -181,17 +182,17 @@ describe('dateMath', function () {
         const thenEx = `${anchor}||+${len}${span}`;
 
         it('should return ' + len + span + ' from now', function () {
-          expect(dateMath.parse(nowEx).format(format)).to.eql(now.add(len, span).format(format));
+          expect(dateMath.parse(nowEx).format(format)).toEqual(now.add(len, span).format(format));
         });
 
         it('should return ' + len + span + ' after ' + anchor, function () {
-          expect(dateMath.parse(thenEx).format(format)).to.eql(
+          expect(dateMath.parse(thenEx).format(format)).toEqual(
             anchored.add(len, span).format(format)
           );
         });
 
         it('should return ' + len + span + ' after forceNow', function () {
-          expect(dateMath.parse(nowEx, { forceNow: anchoredDate }).valueOf()).to.eql(
+          expect(dateMath.parse(nowEx, { forceNow: anchoredDate }).valueOf()).toEqual(
             anchored.add(len, span).valueOf()
           );
         });
@@ -204,30 +205,31 @@ describe('dateMath', function () {
     let anchored;
 
     beforeEach(function () {
-      clock = sinon.useFakeTimers(unix);
+      jest.useFakeTimers('modern');
+      jest.setSystemTime(unix);
       now = moment();
       anchored = moment(anchor);
     });
 
     afterEach(function () {
-      clock.restore();
+      jest.useRealTimers();
     });
 
     spans.forEach((span) => {
       it(`should round now to the beginning of the ${span}`, function () {
-        expect(dateMath.parse('now/' + span).format(format)).to.eql(
+        expect(dateMath.parse('now/' + span).format(format)).toEqual(
           now.startOf(span).format(format)
         );
       });
 
       it(`should round now to the beginning of forceNow's ${span}`, function () {
-        expect(dateMath.parse('now/' + span, { forceNow: anchoredDate }).valueOf()).to.eql(
+        expect(dateMath.parse('now/' + span, { forceNow: anchoredDate }).valueOf()).toEqual(
           anchored.startOf(span).valueOf()
         );
       });
 
       it(`should round now to the end of the ${span}`, function () {
-        expect(dateMath.parse('now/' + span, { roundUp: true }).format(format)).to.eql(
+        expect(dateMath.parse('now/' + span, { roundUp: true }).format(format)).toEqual(
           now.endOf(span).format(format)
         );
       });
@@ -235,7 +237,7 @@ describe('dateMath', function () {
       it(`should round now to the end of forceNow's ${span}`, function () {
         expect(
           dateMath.parse('now/' + span, { roundUp: true, forceNow: anchoredDate }).valueOf()
-        ).to.eql(anchored.endOf(span).valueOf());
+        ).toEqual(anchored.endOf(span).valueOf());
       });
     });
   });
@@ -245,38 +247,39 @@ describe('dateMath', function () {
     let anchored;
 
     beforeEach(function () {
-      clock = sinon.useFakeTimers(unix);
+      jest.useFakeTimers('modern');
+      jest.setSystemTime(unix);
       now = moment();
       anchored = moment(anchor);
     });
 
     afterEach(function () {
-      clock.restore();
+      jest.useRealTimers();
     });
 
     it('should round to the nearest second with 0 value', function () {
       const val = dateMath.parse('now-0s/s').format(format);
-      expect(val).to.eql(now.startOf('s').format(format));
+      expect(val).toEqual(now.startOf('s').format(format));
     });
 
     it('should subtract 17s, rounded to the nearest second', function () {
       const val = dateMath.parse('now-17s/s').format(format);
-      expect(val).to.eql(now.startOf('s').subtract(17, 's').format(format));
+      expect(val).toEqual(now.startOf('s').subtract(17, 's').format(format));
     });
 
     it('should add 555ms, rounded to the nearest millisecond', function () {
       const val = dateMath.parse('now+555ms/ms').format(format);
-      expect(val).to.eql(now.add(555, 'ms').startOf('ms').format(format));
+      expect(val).toEqual(now.add(555, 'ms').startOf('ms').format(format));
     });
 
     it('should subtract 555ms, rounded to the nearest second', function () {
       const val = dateMath.parse('now-555ms/s').format(format);
-      expect(val).to.eql(now.subtract(555, 'ms').startOf('s').format(format));
+      expect(val).toEqual(now.subtract(555, 'ms').startOf('s').format(format));
     });
 
     it('should round weeks to Sunday by default', function () {
       const val = dateMath.parse('now-1w/w');
-      expect(val.isoWeekday()).to.eql(7);
+      expect(val.isoWeekday()).toEqual(7);
     });
 
     it('should round weeks based on the passed moment locale start of week setting', function () {
@@ -286,7 +289,7 @@ describe('dateMath', function () {
         week: { dow: 2 },
       });
       const val = dateMath.parse('now-1w/w', { momentInstance: m });
-      expect(val.isoWeekday()).to.eql(2);
+      expect(val.isoWeekday()).toEqual(2);
     });
 
     it('should round up weeks based on the passed moment locale start of week setting', function () {
@@ -301,79 +304,79 @@ describe('dateMath', function () {
       });
       // The end of the range (rounding up) should be the last day of the week (so one day before)
       // our start of the week, that's why 3 - 1
-      expect(val.isoWeekday()).to.eql(3 - 1);
+      expect(val.isoWeekday()).toEqual(3 - 1);
     });
 
     it('should round relative to forceNow', function () {
       const val = dateMath.parse('now-0s/s', { forceNow: anchoredDate }).valueOf();
-      expect(val).to.eql(anchored.startOf('s').valueOf());
+      expect(val).toEqual(anchored.startOf('s').valueOf());
     });
 
     it('should parse long expressions', () => {
-      expect(dateMath.parse('now-1d/d+8h+50m')).to.be.ok();
+      expect(dateMath.parse('now-1d/d+8h+50m')).toBeTruthy();
     });
   });
 
   describe('used momentjs instance', function () {
     it('should use the default moment instance if parameter not specified', function () {
-      const momentSpy = sinon.spy(moment, 'isMoment');
+      const momentSpy = jest.spyOn(moment, 'isMoment');
       dateMath.parse('now');
-      expect(momentSpy.called).to.be(true);
-      momentSpy.restore();
+      expect(momentSpy).toHaveBeenCalled();
+      momentSpy.mockRestore();
     });
 
     it('should not use default moment instance if parameter is specified', function () {
       const m = momentClone();
-      const momentSpy = sinon.spy(moment, 'isMoment');
-      const cloneSpy = sinon.spy(m, 'isMoment');
+      const momentSpy = jest.spyOn(moment, 'isMoment');
+      const cloneSpy = jest.spyOn(m, 'isMoment');
       dateMath.parse('now', { momentInstance: m });
-      expect(momentSpy.called).to.be(false);
-      expect(cloneSpy.called).to.be(true);
-      momentSpy.restore();
-      cloneSpy.restore();
+      expect(momentSpy).not.toHaveBeenCalled();
+      expect(cloneSpy).toHaveBeenCalled();
+      momentSpy.mockRestore();
+      cloneSpy.mockRestore();
     });
 
     it('should work with multiple different instances', function () {
       const m1 = momentClone();
       const m2 = momentClone();
-      const m1Spy = sinon.spy(m1, 'isMoment');
-      const m2Spy = sinon.spy(m2, 'isMoment');
+      const m1Spy = jest.spyOn(m1, 'isMoment');
+      const m2Spy = jest.spyOn(m2, 'isMoment');
       dateMath.parse('now', { momentInstance: m1 });
-      expect(m1Spy.called).to.be(true);
-      expect(m2Spy.called).to.be(false);
-      m1Spy.resetHistory();
-      m2Spy.resetHistory();
+      expect(m1Spy).toHaveBeenCalled();
+      expect(m2Spy).not.toHaveBeenCalled();
+      m1Spy.mockClear();
+      m2Spy.mockClear();
       dateMath.parse('now', { momentInstance: m2 });
-      expect(m1Spy.called).to.be(false);
-      expect(m2Spy.called).to.be(true);
-      m1Spy.restore();
-      m2Spy.restore();
+      expect(m1Spy).not.toHaveBeenCalled();
+      expect(m2Spy).toHaveBeenCalled();
+      m1Spy.mockRestore();
+      m2Spy.mockRestore();
     });
 
     it('should use global instance after passing an instance', function () {
       const m = momentClone();
-      const momentSpy = sinon.spy(moment, 'isMoment');
-      const cloneSpy = sinon.spy(m, 'isMoment');
+      const momentSpy = jest.spyOn(moment, 'isMoment');
+      const cloneSpy = jest.spyOn(m, 'isMoment');
       dateMath.parse('now', { momentInstance: m });
-      expect(momentSpy.called).to.be(false);
-      expect(cloneSpy.called).to.be(true);
-      momentSpy.resetHistory();
-      cloneSpy.resetHistory();
+      expect(momentSpy).not.toHaveBeenCalled();
+      expect(cloneSpy).toHaveBeenCalled();
+      momentSpy.mockClear();
+      cloneSpy.mockClear();
       dateMath.parse('now');
-      expect(momentSpy.called).to.be(true);
-      expect(cloneSpy.called).to.be(false);
-      momentSpy.restore();
-      cloneSpy.restore();
+      expect(momentSpy).toHaveBeenCalled();
+      expect(cloneSpy).not.toHaveBeenCalled();
+      momentSpy.mockRestore();
+      cloneSpy.mockRestore();
     });
   });
 
   describe('units', function () {
     it('should have units descending for unitsDesc', function () {
-      expect(dateMath.unitsDesc).to.eql(['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms']);
+      expect(dateMath.unitsDesc).toEqual(['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms']);
     });
 
     it('should have units ascending for unitsAsc', function () {
-      expect(dateMath.unitsAsc).to.eql(['ms', 's', 'm', 'h', 'd', 'w', 'M', 'y']);
+      expect(dateMath.unitsAsc).toEqual(['ms', 's', 'm', 'h', 'd', 'w', 'M', 'y']);
     });
   });
 });
diff --git a/packages/elastic-datemath/jest.config.js b/packages/elastic-datemath/jest.config.js
new file mode 100644
index 0000000000000..6a0bd891f1c58
--- /dev/null
+++ b/packages/elastic-datemath/jest.config.js
@@ -0,0 +1,25 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports = {
+  preset: '@kbn/test',
+  rootDir: '../..',
+  roots: ['<rootDir>/packages/elastic-datemath'],
+  testEnvironment: 'jsdom',
+};