Эх сурвалжийг харах

unit tests are migrated from mocha to jest. Added test step to the pipeline.

Ievgen Naida 1 жил өмнө
parent
commit
18d12fa056

+ 2 - 1
.github/workflows/lint.yml

@@ -13,5 +13,6 @@ jobs:
           node-version: '20.x'
       - run: npm ci
       - run: npm run lint
-      - run: npm run prettier
+      - run: npm run format:check
       - run: npm run build
+      - run: npm run test

+ 2 - 1
.gitignore

@@ -37,4 +37,5 @@ lib/settings/styles/timelineKeyframeStyle.js
 lib/settings/styles/timelineRowStyle.js
 lib/settings/styles/timelineStyle.js
 test
-copy.sh
+copy.sh
+coverage/

+ 1 - 0
.vscode/extensions.json

@@ -4,6 +4,7 @@
     "davidanson.vscode-markdownlint",
     "dbaeumer.vscode-eslint",
     "github.vscode-github-actions",
+    "orta.vscode-jest",
     "streetsidesoftware.code-spell-checker"
   ],
   "unwantedRecommendations": []

+ 10 - 4
.vscode/launch.json

@@ -12,11 +12,17 @@
       "webRoot": "${workspaceFolder}"
     },
     {
-      "type": "chrome",
+      "name": "Debug Current Test File",
+      "type": "node",
       "request": "launch",
-      "name": "Launch Test File",
-      "url": "file:///${workspaceFolder}/tests/unittests.html",
-      "webRoot": "${workspaceFolder}"
+      "program": "${workspaceFolder}/node_modules/jest/bin/jest",
+      "args": [
+        "--runTestsByPath",
+        "${relativeFileDirname}/${fileBasename}"
+      ],
+      "console": "integratedTerminal",
+      "internalConsoleOptions": "neverOpen",
+      "port": 9229
     }
   ]
 }

+ 3 - 10
README.md

@@ -403,18 +403,11 @@ Component has no production dependencies when built.
 TypeScript Babel + Webpack is used to pack and transpile the library.
 Mocha and chai are used as test & assertion library.
 
-### Build Tests
-
-To build TypeScript unittests command should be executed:
-
-```bash
-  npm run build-tests
-```
-
 ### Run Tests
 
-Tests execution can be started by opening tests/unittests.html.
-Mocha test libs are hosted on the internet, so connection is required.
+```cmd
+npm run test
+```
 
 ## License
 

+ 2 - 1
lib/animation-timeline.js

@@ -3148,7 +3148,8 @@ var Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
       }
     });
     timeline_defineProperty(_this, "redraw", function () {
-      if (window.requestAnimationFrame) {
+      var _window;
+      if ((_window = window) !== null && _window !== void 0 && _window.requestAnimationFrame) {
         window.requestAnimationFrame(_this._redrawInternal);
       } else {
         _this._redrawInternal();

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
lib/animation-timeline.js.map


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
lib/animation-timeline.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 81
lib/tests/settingsTests.test.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 670
lib/tests/styleTests.test.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 866
lib/tests/timelineTests.test.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 36 - 694
package-lock.json


+ 23 - 11
package.json

@@ -11,37 +11,49 @@
     "@babel/plugin-proposal-object-rest-spread": "7.20.7",
     "@babel/preset-env": "7.24.3",
     "@babel/preset-typescript": "7.24.1",
-    "@types/chai": "4.3.14",
-    "@types/mocha": "10.0.6",
+    "@jest/globals": "^29.7.0",
     "@typescript-eslint/eslint-plugin": "7.3.1",
     "@typescript-eslint/parser": "7.3.1",
+    "babel-jest": "^29.7.0",
     "babel-loader": "9.1.3",
-    "chai": "5.1.0",
     "eslint": "8.57.0",
     "eslint-config-prettier": "9.1.0",
     "eslint-plugin-prettier": "5.1.3",
-    "mocha": "10.3.0",
+    "jest": "^29.7.0",
+    "jest-environment-jsdom": "^29.7.0",
     "prettier": "3.2.5",
+    "ts-jest": "^29.1.2",
     "ts-loader": "9.5.1",
+    "ts-node": "10.9.2",
     "typescript": "5.4.3",
     "webpack": "5.91.0",
     "webpack-cli": "5.1.4"
   },
   "scripts": {
     "start": "echo \"Run npm build and open index.html in your browser. You have to run build command every time files are changed.\" && exit 1",
-    "test": "echo \"Open tests/unittest.html explicitly to execute tests. Build after files are changed.\" && exit 1",
+    "test": "jest --coverage",
     "build-ts-def": "tsc -emitDeclarationOnly",
-    "build": "webpack && npm run build-ts-def && npm run build-tests",
-    "lint": "eslint --ext .ts,.html src --ignore-path .gitignore && prettier \"src/*.ts\" --check --ignore-path .gitignore",
+    "build": "webpack && npm run build-ts-def",
+    "lint": "eslint --ext .ts,.html src tests --ignore-path .gitignore",
     "webpack": "npm run build",
-    "build-tests": "tsc -p tsconfig.tests.json",
-    "format": "prettier --write src/**/*.{ts,js,css,scss,html}",
-    "prettier": "prettier --check src/**/*.{ts,js,css,scss,html}"
+    "format": "prettier --write src/**/*.{ts,js,css,scss,html} tests/**/*.{ts,js,css,scss,html} --ignore-path .gitignore",
+    "format:check": "prettier --check src/**/*.{ts,js,css,scss,html} tests/**/*.{ts,js,css,scss,html} --ignore-path .gitignore",
+    "check": "npm run lint && npm run format:check && npm run test"
   },
   "repository": {
     "type": "git",
     "url": "git+https://github.com/ievgennaida/js-animation-timeline-control.git"
   },
+  "jest": {
+    "testEnvironment": "jsdom",
+    "coveragePathIgnorePatterns": [
+      "<rootDir>/src/animation-timeline.ts",
+      "<rootDir>/src/enums",
+      "<rootDir>/src/models",
+      "<rootDir>/lib",
+      "<rootDir>/tests"
+    ]
+  },
   "keywords": [
     "js",
     "animation",
@@ -59,4 +71,4 @@
     "url": "https://github.com/ievgennaida/js-animation-timeline-control/issues"
   },
   "homepage": "https://ievgennaida.github.io/animation-timeline-control/index.html"
-}
+}

+ 1 - 1
src/timeline.ts

@@ -2150,7 +2150,7 @@ export class Timeline extends TimelineEventsEmitter {
   };
 
   redraw = (): void => {
-    if (window.requestAnimationFrame) {
+    if (window?.requestAnimationFrame) {
       window.requestAnimationFrame(this._redrawInternal);
     } else {
       this._redrawInternal();

+ 0 - 25
tests/README.md

@@ -1,25 +0,0 @@
-# Run Tests
-
-Build first:
-
-```CMD
-npm run build
-```
-
-To run tests you can open unittests.html in a the browser.
-
-Note: folder "lib\tests" is autogenerated and contains build output from the local tests folder.
-To add new tests group create a new  *.ts file and place it in the tests folder.
-
-## Debug
-
-VSCode is used as IDE and configuration is included to the project sources.
-
-To debug project you should run command once files are changed:
-
-```cmd
-npm run build
-```
-
-Then navigate to the debug window and click 'Launch Test File'.
-Put breakpoint in any typescript tests file to and refresh page or test to run debugger.

+ 89 - 0
tests/settingsTests.spec.ts

@@ -0,0 +1,89 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { expect } from '@jest/globals';
+import { TimelineKeyframeStyle, TimelineOptions, TimelineRowStyle, TimelineUtils, defaultTimelineOptions } from '../src/animation-timeline';
+
+describe('TimelineUtils.mergeOptions', () => {
+  it('Top level options are merged', () => {
+    const defOptions = defaultTimelineOptions as TimelineOptions;
+    const options = { id: 'new id', snapStep: 10, snapEnabled: true } as TimelineOptions;
+    const merged = TimelineUtils.mergeOptions(defOptions, options);
+    expect(merged.id).toBe(options.id);
+    expect(merged.snapEnabled).toBe(options.snapEnabled);
+    expect(merged.snapStep).toBe(options.snapStep);
+    expect(merged.labelsColor).toBe(defOptions.labelsColor);
+    expect(merged.leftMargin).toBe(defOptions.leftMargin);
+    expect(merged.selectionColor).toBe(defOptions.selectionColor);
+
+    console.log('initial options should not be affected');
+    expect(options.selectionColor === undefined).toBe(true);
+  });
+  it('HTML element no need to copy, value is reset.', () => {
+    const defOptions = defaultTimelineOptions as TimelineOptions;
+    const options = { id: window.document.childNodes[0] } as TimelineOptions;
+    console.log('HTML element should exists for the test to be executed');
+    expect(options.id).toBeTruthy();
+    const merged = TimelineUtils.mergeOptions(defOptions, options);
+    expect(merged.id).toBe(options.id);
+  });
+  it('HTML element can be replaced during the merge', () => {
+    const defOptions = defaultTimelineOptions as TimelineOptions;
+    let options = { id: window.document.childNodes[0] } as TimelineOptions;
+    console.log('HTML element should exists for the test to be executed');
+    expect(options.id).toBeTruthy();
+
+    let merged = TimelineUtils.mergeOptions(defOptions, options);
+    expect(merged.id).toBe(options.id);
+    const selectedElement = window.document.childNodes[1];
+    console.log('HTML element should exists for the test to be executed');
+    expect(selectedElement).toBeTruthy();
+    options = { id: selectedElement } as TimelineOptions;
+    merged = TimelineUtils.mergeOptions(merged, options);
+    expect(merged.id).toBe(selectedElement);
+
+    options = { snapEnabled: true } as TimelineOptions;
+    merged = TimelineUtils.mergeOptions(merged, options);
+    expect(merged.id).toBe(selectedElement);
+    expect(merged.snapEnabled).toBe(true);
+  });
+  it('Default styles are merged', () => {
+    const options = { id: 'new id', snapStep: 10, snapEnabled: true } as TimelineOptions;
+    const merged = TimelineUtils.mergeOptions(defaultTimelineOptions as TimelineOptions, options);
+    expect(merged.id).toBe(options.id);
+    console.log('Row style cannot be null');
+    expect(!!merged.rowsStyle).toBe(true);
+    console.log('Keyframes style cannot be null');
+    expect(!!merged.rowsStyle?.keyframesStyle).toBe(true);
+  });
+
+  it('Deep styles are merged', () => {
+    const options = {
+      id: 'new id',
+      snapStep: 10,
+      headerHeight: 44,
+      snapEnabled: true,
+      rowsStyle: {
+        height: 100,
+        keyframesStyle: {
+          hidden: true,
+          draggable: false,
+        } as TimelineKeyframeStyle,
+      } as TimelineRowStyle,
+    } as TimelineOptions;
+    const merged = TimelineUtils.mergeOptions(defaultTimelineOptions as TimelineOptions, options);
+    expect(merged.id).toBe('new id');
+    expect(merged.headerHeight).toBe(44);
+    expect(merged.rowsStyle?.height).toBe(100);
+    const defOptions = defaultTimelineOptions as TimelineOptions;
+    expect(merged.rowsStyle?.keyframesStyle?.shape).toBe(defOptions.rowsStyle?.keyframesStyle?.shape);
+  });
+  it('Original options are not affected', () => {
+    const options = {
+      id: 'new id',
+      snapStep: 10,
+    } as TimelineOptions;
+    const merged = TimelineUtils.mergeOptions(defaultTimelineOptions as TimelineOptions, options);
+    expect(merged.id).toBe('new id');
+    expect(merged.snapStep).toBe(10);
+    expect(options.headerHeight === undefined).toBe(true);
+  });
+});

+ 34 - 27
tests/settingsTests.test.ts

@@ -1,50 +1,57 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
-import { TimelineRowStyle, TimelineOptions, defaultTimelineOptions, TimelineKeyframeStyle, TimelineUtils } from '../lib/animation-timeline';
+
+import { expect } from '@jest/globals';
+import { TimelineKeyframeStyle, TimelineOptions, TimelineRowStyle, TimelineUtils, defaultTimelineOptions } from '../src/animation-timeline';
 
 describe('TimelineUtils.mergeOptions', () => {
   it('Top level options are merged', () => {
     const defOptions = defaultTimelineOptions as TimelineOptions;
     const options = { id: 'new id', snapStep: 10, snapEnabled: true } as TimelineOptions;
     const merged = TimelineUtils.mergeOptions(defOptions, options);
-    chai.expect(merged.id).equal(options.id);
-    chai.expect(merged.snapEnabled).equal(options.snapEnabled);
-    chai.expect(merged.snapStep).equal(options.snapStep);
-    chai.expect(merged.labelsColor).equal(defOptions.labelsColor);
-    chai.expect(merged.leftMargin).equal(defOptions.leftMargin);
-    chai.expect(merged.selectionColor).equal(defOptions.selectionColor);
-
-    chai.expect(options.selectionColor === undefined).equal(true, 'initial options should not be affected');
+    expect(merged.id).toBe(options.id);
+    expect(merged.snapEnabled).toBe(options.snapEnabled);
+    expect(merged.snapStep).toBe(options.snapStep);
+    expect(merged.labelsColor).toBe(defOptions.labelsColor);
+    expect(merged.leftMargin).toBe(defOptions.leftMargin);
+    expect(merged.selectionColor).toBe(defOptions.selectionColor);
+    console.log('initial options should not be affected');
+    expect(options.selectionColor === undefined).toBe(true);
   });
   it('HTML element no need to copy, value is reset.', () => {
     const defOptions = defaultTimelineOptions as TimelineOptions;
     const options = { id: window.document.childNodes[0] } as TimelineOptions;
-    chai.assert(options.id, 'HTML element should exists for the test to be executed');
+    console.log('HTML element should exists for the test to be executed');
+    expect(options.id).toBeTruthy();
     const merged = TimelineUtils.mergeOptions(defOptions, options);
-    chai.expect(merged.id).equal(options.id);
+    expect(merged.id).toBe(options.id);
   });
   it('HTML element can be replaced during the merge', () => {
     const defOptions = defaultTimelineOptions as TimelineOptions;
     let options = { id: window.document.childNodes[0] } as TimelineOptions;
-    chai.assert(options.id, 'HTML element should exists for the test to be executed');
+    console.log('HTML element should exists for the test to be executed');
+    expect(options.id).toBeTruthy();
     let merged = TimelineUtils.mergeOptions(defOptions, options);
-    chai.expect(merged.id).equal(options.id);
+    expect(merged.id).toBe(options.id);
     const selectedElement = window.document.childNodes[1];
-    chai.assert(selectedElement, 'HTML element should exists for the test to be executed');
+    console.log('HTML element should exists for the test to be executed');
+    expect(selectedElement).toBeTruthy();
     options = { id: selectedElement } as TimelineOptions;
     merged = TimelineUtils.mergeOptions(merged, options);
-    chai.expect(merged.id).equal(selectedElement);
+    expect(merged.id).toBe(selectedElement);
 
     options = { snapEnabled: true } as TimelineOptions;
     merged = TimelineUtils.mergeOptions(merged, options);
-    chai.expect(merged.id).equal(selectedElement);
-    chai.expect(merged.snapEnabled).equal(true);
+    expect(merged.id).toBe(selectedElement);
+    expect(merged.snapEnabled).toBe(true);
   });
   it('Default styles are merged', () => {
     const options = { id: 'new id', snapStep: 10, snapEnabled: true } as TimelineOptions;
     const merged = TimelineUtils.mergeOptions(defaultTimelineOptions as TimelineOptions, options);
-    chai.expect(merged.id).equal(options.id);
-    chai.expect(!!merged.rowsStyle).equal(true, 'Row style cannot be null');
-    chai.expect(!!merged.rowsStyle?.keyframesStyle).equal(true, 'Keyframes style cannot be null');
+    expect(merged.id).toBe(options.id);
+    console.log('Row style cannot be null');
+    expect(!!merged.rowsStyle).toBe(true);
+    console.log('Keyframes style cannot be null');
+    expect(!!merged.rowsStyle?.keyframesStyle).toBe(true);
   });
 
   it('Deep styles are merged', () => {
@@ -62,11 +69,11 @@ describe('TimelineUtils.mergeOptions', () => {
       } as TimelineRowStyle,
     } as TimelineOptions;
     const merged = TimelineUtils.mergeOptions(defaultTimelineOptions as TimelineOptions, options);
-    chai.expect(merged.id).equal('new id');
-    chai.expect(merged.headerHeight).equal(44);
-    chai.expect(merged.rowsStyle?.height).equal(100);
+    expect(merged.id).toBe('new id');
+    expect(merged.headerHeight).toBe(44);
+    expect(merged.rowsStyle?.height).toBe(100);
     const defOptions = defaultTimelineOptions as TimelineOptions;
-    chai.expect(merged.rowsStyle?.keyframesStyle?.shape, defOptions.rowsStyle?.keyframesStyle?.shape);
+    expect(merged.rowsStyle?.keyframesStyle?.shape).toBe(defOptions.rowsStyle?.keyframesStyle?.shape);
   });
   it('Original options are not affected', () => {
     const options = {
@@ -74,8 +81,8 @@ describe('TimelineUtils.mergeOptions', () => {
       snapStep: 10,
     } as TimelineOptions;
     const merged = TimelineUtils.mergeOptions(defaultTimelineOptions as TimelineOptions, options);
-    chai.expect(merged.id, 'new id');
-    chai.expect(merged.snapStep).equal(10);
-    chai.expect(options.headerHeight === undefined).equal(true);
+    expect(merged.id).toBe('new id');
+    expect(merged.snapStep).toBe(10);
+    expect(options.headerHeight === undefined).toBe(true);
   });
 });

+ 69 - 68
tests/styleTests.test.ts

@@ -1,4 +1,5 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
+import { expect } from '@jest/globals';
 import {
   TimelineStyleUtils,
   TimelineKeyframeShape,
@@ -10,168 +11,168 @@ import {
   TimelineOptions,
   defaultTimelineKeyframeStyle,
   TimelineUtils,
-} from '../lib/animation-timeline';
-import { TimelineGroup } from '../lib/models/timelineGroup';
-import { TimelineGroupStyle } from '../lib/settings/styles/timelineGroupStyle';
+} from '../src/animation-timeline';
+import { TimelineGroup } from '../src/models/timelineGroup';
+import { TimelineGroupStyle } from '../src/settings/styles/timelineGroupStyle';
 
 describe('TimelineStyleUtils', () => {
   describe('TimelineStyleUtils.getFirstSet', () => {
     it('Bool values. Default returned, empty list', () => {
       const defaultValue = false;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue)).toBe(false);
     });
     it('Bool values. Default returned, undefined values', () => {
       const defaultValue = false;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).toBe(false);
     });
     it('Bool values. True as default is returned', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).equal(true);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).toBe(true);
     });
     it('Bool values. False is returned as first set, default ignored.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, false)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, false)).toBe(false);
     });
 
     it('Bool values. False is returned as first set, default ignored.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, undefined)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, undefined)).toBe(false);
     });
 
     it('Bool values. False is returned as first set, all values valid.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, true)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, true)).toBe(false);
     });
     it('Bool values. True is returned as first set, all values valid.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, true, false)).equal(true);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, true, false)).toBe(true);
     });
 
     it('Bool values. Default returned, empty list', () => {
       const defaultValue = false;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue)).toBe(false);
     });
     it('Bool values. Default returned, undefined values', () => {
       const defaultValue = false;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).toBe(false);
     });
     it('Bool values. True as default is returned', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).equal(true);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, null)).toBe(true);
     });
     it('Bool values. False is returned as first set, default ignored.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, false)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, undefined, false)).toBe(false);
     });
 
     it('Bool values. False is returned as first set, default ignored.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, undefined)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, undefined)).toBe(false);
     });
 
     it('Bool values. False is returned as first set, all values valid.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, true)).equal(false);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, false, true)).toBe(false);
     });
     it('Bool values. True is returned as first set, all values valid.', () => {
       const defaultValue = true;
-      chai.expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, true, false)).equal(true);
+      expect(TimelineStyleUtils.getFirstSet<boolean>(defaultValue, true, false)).toBe(true);
     });
     it('Number values. 5 returned, empty list', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue)).equal(5);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue)).toBe(5);
     });
     it('Number values. Default returned, undefined values', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, null)).equal(5);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, null)).toBe(5);
     });
     it('Number values. 5 as default is returned', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, null)).equal(5);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, null)).toBe(5);
     });
     it('Number values. 0 is returned as valid option', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, null, 0)).equal(0);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, null, 0)).toBe(0);
     });
     it('Number values. 0 is returned as valid option test #2', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 0, undefined, null, 2)).equal(0);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 0, undefined, null, 2)).toBe(0);
     });
     it('Number values. False is returned as first set, default ignored.', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, 1)).equal(1);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, undefined, 1)).toBe(1);
     });
 
     it('Number values. False is returned as first set, default ignored.', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 1, undefined)).equal(1);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 1, undefined)).toBe(1);
     });
 
     it('Number values. False is returned as first set, all values valid.', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 2, 1)).equal(2);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 2, 1)).toBe(2);
     });
     it('Number values. First valid is returned.', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 0, 2)).equal(0);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 0, 2)).toBe(0);
     });
     it('Number values. First valid is returned not zero.', () => {
       const defaultValue = 5;
-      chai.expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 1, 2)).equal(1);
+      expect(TimelineStyleUtils.getFirstSet<number>(defaultValue, 1, 2)).toBe(1);
     });
     it('String values. Default value is returned', () => {
       const defaultValue = 'test';
-      chai.expect(TimelineStyleUtils.getFirstSet(defaultValue)).equal('test');
+      expect(TimelineStyleUtils.getFirstSet(defaultValue)).toBe('test');
     });
     it('String values. Default returned, undefined values', () => {
       const defaultValue = 'test';
-      chai.expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, undefined, null)).equal('test');
+      expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, undefined, null)).toBe('test');
     });
     it('String values. Default returned, undefined values. test #2', () => {
       const defaultValue = 'test';
-      chai.expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, null, undefined)).equal(defaultValue);
+      expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, null, undefined)).toBe(defaultValue);
     });
     it('String values. First set value is returned before invalid.', () => {
       const defaultValue = 'test';
-      chai.expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, undefined, 'test2')).equal('test2');
+      expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, undefined, 'test2')).toBe('test2');
     });
 
     it('String values. First set value is returned', () => {
       const defaultValue = 'test';
-      chai.expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, 'test2', undefined)).equal('test2');
+      expect(TimelineStyleUtils.getFirstSet<string>(defaultValue, 'test2', undefined)).toBe('test2');
     });
 
     /** First Negative Value. */
     it('First negative Bool values. Default returned, empty list', () => {
       const defaultValue = false;
       const firstNegativeIsReturned = true;
-      chai.expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned)).equal(false);
+      expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned)).toBe(false);
     });
     it('First negative Bool values. Default returned, undefined values', () => {
       const defaultValue = false;
       const firstNegativeIsReturned = true;
-      chai.expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, undefined, null)).equal(false);
+      expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, undefined, null)).toBe(false);
     });
     it('First negative Bool values. Bool values. True as default is returned', () => {
       const defaultValue = true;
       const firstNegativeIsReturned = true;
-      chai.expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, undefined, null)).equal(true);
+      expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, undefined, null)).toBe(true);
     });
     it('First negative Bool values.Bool values. False is returned as first set, default ignored.', () => {
       const defaultValue = true;
       const firstNegativeIsReturned = true;
-      chai.expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, true, false)).equal(false);
+      expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, true, false)).toBe(false);
     });
     it('First negative Bool values.Bool values. False is returned as second set.', () => {
       const defaultValue = true;
       const firstNegativeIsReturned = true;
-      chai.expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, false, true)).equal(false);
+      expect(TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, false, true)).toBe(false);
     });
     it('First negative Bool values. Default is ignored..', () => {
       const defaultValue = false;
       const firstNegativeIsReturned = true;
       const returnedValue = TimelineStyleUtils.getValue<boolean>(defaultValue, firstNegativeIsReturned, true, true);
-      chai.expect(returnedValue).equal(true);
+      expect(returnedValue).toBe(true);
     });
   });
   describe('Draggable', () => {
@@ -187,7 +188,7 @@ describe('TimelineStyleUtils', () => {
         style: { shape: TimelineKeyframeShape.Rect } as TimelineKeyframeStyle,
       } as TimelineKeyframe;
       const keyframeDraggable = TimelineStyleUtils.keyframeDraggable(keyframe, null, null, timelineOptions);
-      chai.expect(keyframeDraggable).equal(true);
+      expect(keyframeDraggable).toBe(true);
     });
     it('Keyframe is draggable', () => {
       const timelineOptions = {
@@ -197,7 +198,7 @@ describe('TimelineStyleUtils', () => {
       } as TimelineOptions;
 
       const keyframe = { draggable: true, style: { shape: TimelineKeyframeShape.Rect } } as TimelineKeyframe;
-      chai.expect(TimelineStyleUtils.keyframeDraggable(keyframe, null, null, timelineOptions)).equal(true);
+      expect(TimelineStyleUtils.keyframeDraggable(keyframe, null, null, timelineOptions)).toBe(true);
     });
 
     it('Keyframe is not draggable', () => {
@@ -208,7 +209,7 @@ describe('TimelineStyleUtils', () => {
       } as TimelineOptions;
 
       const keyframe = { draggable: false, style: { shape: TimelineKeyframeShape.Rect } } as TimelineKeyframe;
-      chai.expect(TimelineStyleUtils.keyframeDraggable(keyframe, null, null, timelineOptions)).equal(false);
+      expect(TimelineStyleUtils.keyframeDraggable(keyframe, null, null, timelineOptions)).toBe(false);
     });
 
     it('Keyframe is draggable cannot override row', () => {
@@ -220,7 +221,7 @@ describe('TimelineStyleUtils', () => {
       const rowModel = { keyframesDraggable: false, keyframesStyle: { keyframesStyle: { shape: TimelineKeyframeShape.Rect } } } as TimelineRow;
       const keyframe = { draggable: true, style: { shape: TimelineKeyframeShape.Rect } } as TimelineKeyframe;
       const value = TimelineStyleUtils.keyframeDraggable(keyframe, null, rowModel, timelineOptions);
-      chai.expect(value).equal(false);
+      expect(value).toBe(false);
     });
 
     it('Keyframes are not draggable by row settings', () => {
@@ -234,7 +235,7 @@ describe('TimelineStyleUtils', () => {
       const rowModel = { keyframesDraggable: false, style: { keyframesStyle: { shape: TimelineKeyframeShape.Rect } } } as TimelineRow;
       const keyframe = { draggable: true, style: { shape: TimelineKeyframeShape.Rect } } as TimelineKeyframe;
       const isDraggable = TimelineStyleUtils.keyframeDraggable(keyframe, null, rowModel, timelineOptions);
-      chai.expect(isDraggable).equal(false);
+      expect(isDraggable).toBe(false);
     });
     it('Keyframes are draggable by row', () => {
       const timelineOptions = {
@@ -247,7 +248,7 @@ describe('TimelineStyleUtils', () => {
       const rowModel = { keyframesDraggable: true, keyframesStyle: { keyframesStyle: { shape: TimelineKeyframeShape.Rect } } } as TimelineRow;
       const keyframe = { draggable: true, style: { shape: TimelineKeyframeShape.Rect } } as TimelineKeyframe;
       const returnedValue = TimelineStyleUtils.keyframeDraggable(keyframe, null, rowModel, timelineOptions);
-      chai.expect(returnedValue).equal(true);
+      expect(returnedValue).toBe(true);
     });
     it('Keyframes are not draggable while turned off on the top level.', () => {
       const timelineOptions = {
@@ -261,7 +262,7 @@ describe('TimelineStyleUtils', () => {
       const rowModel = { keyframesDraggable: false, keyframesStyle: { keyframesStyle: { shape: TimelineKeyframeShape.Rect } } } as TimelineRow;
       const keyframe = { draggable: true, style: { shape: TimelineKeyframeShape.Rect } } as TimelineKeyframe;
       const isDraggable = TimelineStyleUtils.keyframeDraggable(keyframe, null, rowModel, timelineOptions);
-      chai.expect(isDraggable).equal(false);
+      expect(isDraggable).toBe(false);
     });
     it('Groups are draggable by default', () => {
       const timelineOptions = {
@@ -273,7 +274,7 @@ describe('TimelineStyleUtils', () => {
         } as TimelineRowStyle,
       } as TimelineOptions;
       const rowModel = { keyframesDraggable: true, keyframesStyle: { keyframesStyle: { shape: TimelineKeyframeShape.Rect } } } as TimelineRow;
-      chai.expect(TimelineStyleUtils.groupDraggable(null, rowModel, timelineOptions)).equal(true);
+      expect(TimelineStyleUtils.groupDraggable(null, rowModel, timelineOptions)).toBe(true);
     });
 
     it('Group is draggable', () => {
@@ -286,7 +287,7 @@ describe('TimelineStyleUtils', () => {
         } as TimelineRowStyle,
       } as TimelineOptions;
       const rowModel = { keyframesDraggable: true, groupDraggable: true, keyframesStyle: { keyframesStyle: { shape: TimelineKeyframeShape.Rect } } } as TimelineRow;
-      chai.expect(TimelineStyleUtils.groupDraggable(null, rowModel, timelineOptions)).equal(true);
+      expect(TimelineStyleUtils.groupDraggable(null, rowModel, timelineOptions)).toBe(true);
     });
 
     it('Group is not draggable by row settings', () => {
@@ -306,7 +307,7 @@ describe('TimelineStyleUtils', () => {
         keyframesStyle: { shape: TimelineKeyframeShape.Rect },
       } as TimelineRow;
       const isDraggable = TimelineStyleUtils.groupDraggable(null, rowModel, timelineOptions);
-      chai.expect(isDraggable).equal(false);
+      expect(isDraggable).toBe(false);
     });
   });
   describe('Group style options', () => {
@@ -344,8 +345,8 @@ describe('TimelineStyleUtils', () => {
         style: { shape: TimelineKeyframeShape.Rect },
       } as TimelineKeyframe;
       const value = TimelineStyleUtils.groupFillColor(timelineOptions, keyframe.group, rowModel.style);
-      chai.expect(value).equal(defaultGroupStyle.fillColor);
-      chai.expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).equal(defaultGroupStyle.marginTop);
+      expect(value).toBe(defaultGroupStyle.fillColor);
+      expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).toBe(defaultGroupStyle.marginTop);
     });
 
     it('Groups options style is applied', () => {
@@ -369,8 +370,8 @@ describe('TimelineStyleUtils', () => {
         style: { shape: TimelineKeyframeShape.Rect },
       } as TimelineKeyframe;
       const value = TimelineStyleUtils.groupFillColor(timelineOptions, keyframe.group, rowModel.style);
-      chai.expect(value).equal(groupOptionsStyle.fillColor);
-      chai.expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).equal(groupOptionsStyle.marginTop);
+      expect(value).toBe(groupOptionsStyle.fillColor);
+      expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).toBe(groupOptionsStyle.marginTop);
     });
 
     it('Groups rows group options are applied', () => {
@@ -400,8 +401,8 @@ describe('TimelineStyleUtils', () => {
         style: { shape: TimelineKeyframeShape.Rect },
       } as TimelineKeyframe;
       const value = TimelineStyleUtils.groupFillColor(timelineOptions, keyframe.group, rowModel.style);
-      chai.expect(value).equal(groupsRowStyle.fillColor);
-      chai.expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).equal(groupsRowStyle.marginTop);
+      expect(value).toBe(groupsRowStyle.fillColor);
+      expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).toBe(groupsRowStyle.marginTop);
     });
 
     it('Groups keyframe group options are applied', () => {
@@ -424,8 +425,8 @@ describe('TimelineStyleUtils', () => {
         style: { shape: TimelineKeyframeShape.Rect },
       } as TimelineKeyframe;
       const value = TimelineStyleUtils.groupFillColor(timelineOptions, keyframe.group, rowModel.style);
-      chai.expect(value).equal(keyframesGroupsStyle.fillColor);
-      chai.expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).equal(keyframesGroupsStyle.marginTop);
+      expect(value).toBe(keyframesGroupsStyle.fillColor);
+      expect(TimelineStyleUtils.groupMarginTop(timelineOptions, keyframe.group, rowModel.style)).toBe(keyframesGroupsStyle.marginTop);
     });
   });
   describe('Row styles', () => {
@@ -438,7 +439,7 @@ describe('TimelineStyleUtils', () => {
       } as TimelineOptions;
 
       const rowsStyle = { height: 50 } as TimelineRowStyle;
-      chai.expect(TimelineStyleUtils.getRowHeight(rowsStyle, timelineOptions)).equal(rowsStyle.height);
+      expect(TimelineStyleUtils.getRowHeight(rowsStyle, timelineOptions)).toBe(rowsStyle.height);
     });
     it('Height is taken from global settings', () => {
       const timelineOptions = {
@@ -449,7 +450,7 @@ describe('TimelineStyleUtils', () => {
       } as TimelineOptions;
 
       const rowsStyle = {} as TimelineRowStyle;
-      chai.expect(TimelineStyleUtils.getRowHeight(rowsStyle, timelineOptions)).equal(timelineOptions.rowsStyle?.height);
+      expect(TimelineStyleUtils.getRowHeight(rowsStyle, timelineOptions)).toBe(timelineOptions.rowsStyle?.height);
     });
     it('Margin bottom is taken from global settings', () => {
       const timelineOptions = {
@@ -461,7 +462,7 @@ describe('TimelineStyleUtils', () => {
       } as TimelineOptions;
 
       const rowsStyle = {} as TimelineRowStyle;
-      chai.expect(TimelineStyleUtils.getRowMarginBottom(rowsStyle, timelineOptions)).equal(timelineOptions.rowsStyle?.marginBottom);
+      expect(TimelineStyleUtils.getRowMarginBottom(rowsStyle, timelineOptions)).toBe(timelineOptions.rowsStyle?.marginBottom);
     });
     it('Margin bottom is taken from row settings', () => {
       const timelineOptions = {
@@ -473,7 +474,7 @@ describe('TimelineStyleUtils', () => {
       } as TimelineOptions;
 
       const rowsStyle = { marginBottom: 43 } as TimelineRowStyle;
-      chai.expect(TimelineStyleUtils.getRowMarginBottom(rowsStyle, timelineOptions)).equal(rowsStyle.marginBottom);
+      expect(TimelineStyleUtils.getRowMarginBottom(rowsStyle, timelineOptions)).toBe(rowsStyle.marginBottom);
     });
   });
 
@@ -486,21 +487,21 @@ describe('TimelineStyleUtils', () => {
       expectedStyle: TimelineKeyframeStyle,
     ) => {
       const fillColor = TimelineStyleUtils.keyframeFillColor(keyframe, group, rowStyle, options);
-      chai.expect(fillColor).equal(expectedStyle.fillColor);
+      expect(fillColor).toBe(expectedStyle.fillColor);
       const keyframeHeight = TimelineStyleUtils.keyframeHeight(keyframe, group, rowStyle, options);
-      chai.expect(keyframeHeight).equal(expectedStyle.height);
+      expect(keyframeHeight).toBe(expectedStyle.height);
       const selectedFillColor = TimelineStyleUtils.keyframeSelectedFillColor(keyframe, group, rowStyle, options);
-      chai.expect(selectedFillColor).equal(expectedStyle.selectedFillColor);
+      expect(selectedFillColor).toBe(expectedStyle.selectedFillColor);
       const keyframeSelectedStrokeColor = TimelineStyleUtils.keyframeSelectedStrokeColor(keyframe, group || null, rowStyle, options);
-      chai.expect(keyframeSelectedStrokeColor).equal(expectedStyle.selectedStrokeColor);
+      expect(keyframeSelectedStrokeColor).toBe(expectedStyle.selectedStrokeColor);
       const shape = TimelineStyleUtils.keyframeShape(keyframe, group, rowStyle, options);
-      chai.expect(shape).equal(expectedStyle.shape);
+      expect(shape).toBe(expectedStyle.shape);
       const keyframeStrokeColor = TimelineStyleUtils.keyframeStrokeColor(keyframe, group, rowStyle, options);
-      chai.expect(keyframeStrokeColor).equal(expectedStyle.strokeColor);
+      expect(keyframeStrokeColor).toBe(expectedStyle.strokeColor);
       const keyframeStrokeThickness = TimelineStyleUtils.keyframeStrokeThickness(keyframe, group, rowStyle, options);
-      chai.expect(keyframeStrokeThickness).equal(expectedStyle.strokeThickness);
+      expect(keyframeStrokeThickness).toBe(expectedStyle.strokeThickness);
       const keyframeWidth = TimelineStyleUtils.keyframeWidth(keyframe, group, rowStyle, options);
-      chai.expect(keyframeWidth).equal(expectedStyle.width);
+      expect(keyframeWidth).toBe(expectedStyle.width);
     };
     it('Default keyframe styles are applied.', () => {
       const timelineOptions = {

+ 181 - 174
tests/timelineTests.test.ts

@@ -1,4 +1,5 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
+import { expect } from '@jest/globals';
 import {
   TimelineSelectionMode,
   TimelineKeyframe,
@@ -13,7 +14,7 @@ import {
   TimelineKeyframeStyle,
   TimelineUtils,
   TimelineKeyframeShape,
-} from '../lib/animation-timeline';
+} from '../src/animation-timeline';
 
 describe('Timeline', () => {
   describe('_findDraggableElement', () => {
@@ -34,7 +35,8 @@ describe('Timeline', () => {
         throw new Error('element cannot be empty');
       }
 
-      chai.expect(element.type).equal(TimelineElementType.Keyframe, TimelineElementType.Keyframe + ' should be selected');
+      console.log(TimelineElementType.Keyframe + ' should be selected');
+      expect(element.type).toBe(TimelineElementType.Keyframe);
     });
     it('Timeline should be selected', () => {
       const timeline = new Timeline();
@@ -52,7 +54,8 @@ describe('Timeline', () => {
       if (!element) {
         throw new Error('element cannot be empty');
       }
-      chai.expect(element.type).equal(TimelineElementType.Timeline, TimelineElementType.Timeline + ' should be selected');
+      console.log(TimelineElementType.Timeline + ' should be selected');
+      expect(element.type).toBe(TimelineElementType.Timeline);
     });
     it('Timeline should taken first', () => {
       const timeline = new Timeline();
@@ -78,9 +81,11 @@ describe('Timeline', () => {
       if (!element) {
         throw new Error('element cannot be empty');
       }
-      chai.expect(element.type).equal(TimelineElementType.Timeline, TimelineElementType.Timeline + ' should be selected');
+
+      console.log(TimelineElementType.Timeline + ' should be selected');
+      expect(element.type).toBe(TimelineElementType.Timeline);
       // Keyframe with value 5 should be selected
-      chai.expect(element.val).equal(5);
+      expect(element.val).toBe(5);
     });
 
     it('Group should be found under the value', () => {
@@ -95,7 +100,8 @@ describe('Timeline', () => {
       if (!element) {
         throw new Error('element cannot be empty');
       }
-      chai.expect(element.type).equal(TimelineElementType.Group, TimelineElementType.Group + ' should be selected');
+      console.log(TimelineElementType.Group + ' should be selected');
+      expect(element.type).toBe(TimelineElementType.Group);
     });
     it('closest keyframe should be returned', () => {
       const timeline = new Timeline();
@@ -114,8 +120,8 @@ describe('Timeline', () => {
         } as TimelineElement,
       ];
       const element = timeline._findDraggableElement(elements, 5);
-      chai.assert(element);
-      chai.expect(element.val).equal(elements[1].val);
+      expect(element).toBeTruthy();
+      expect(element?.val).toBe(elements[1].val);
     });
     it('Keyframes are not draggable by global settings', () => {
       const timeline = new Timeline();
@@ -143,8 +149,9 @@ describe('Timeline', () => {
         } as TimelineRowStyle,
       } as TimelineOptions;
       const element = timeline._findDraggableElement(elements, 5);
-      chai.assert(element);
-      chai.expect(element.type).equal(TimelineElementType.Group, 'Group should be selected');
+      expect(element);
+      console.log('Group should be selected');
+      expect(element?.type).toBe(TimelineElementType.Group);
     });
     it('Timeline. Keyframes are not draggable by row settings', () => {
       const timeline = new Timeline();
@@ -166,9 +173,9 @@ describe('Timeline', () => {
       ];
       // Apply global options::
       const element = timeline._findDraggableElement(elements, 4);
-      chai.assert(element);
+      expect(element);
       // Keyframe with value 5 should be selected as draggable
-      chai.expect(element.val).equal(5);
+      expect(element?.val).toBe(5);
     });
 
     it('Keyframes are draggable', () => {
@@ -202,9 +209,9 @@ describe('Timeline', () => {
       ];
       // Apply global options::
       const element = timeline._findDraggableElement(elements, 4);
-      chai.assert(element);
+      expect(element);
       // Keyframe with value 5 should be selected as draggable
-      chai.expect(element.val).equal(5);
+      expect(element?.val).toBe(5);
     });
   });
   describe('select', () => {
@@ -220,20 +227,20 @@ describe('Timeline', () => {
       const timeline = new Timeline();
       timeline._model = model;
       const element = timeline.selectAllKeyframes();
-      chai.expect(element.selectionChanged).equal(true);
+      expect(element.selectionChanged).toBe(true);
       let changed = 0;
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row && row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
-            chai.expect(keyframe.selected).equal(true);
+            expect(keyframe.selected).toBe(true);
             changed++;
           });
         }
       });
 
-      chai.expect(element.selected.length).equal(changed);
+      expect(element.selected.length).toBe(changed);
     });
     it('Select all selectable', () => {
       const timeline = new Timeline();
@@ -244,7 +251,7 @@ describe('Timeline', () => {
       let selectable = 0;
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             keyframe.selected = false;
@@ -257,15 +264,15 @@ describe('Timeline', () => {
         }
       });
       const selectionResults = timeline.select(element);
-      chai.expect(selectionResults.changed.length).equal(selectable);
-      chai.expect(selectionResults.selected.length).equal(selectable);
+      expect(selectionResults.changed.length).toBe(selectable);
+      expect(selectionResults.selected.length).toBe(selectable);
     });
     it('Deselect all', () => {
       const timeline = new Timeline();
       timeline._model = model;
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             keyframe.selectable = true;
@@ -275,14 +282,14 @@ describe('Timeline', () => {
       });
       // deselect all
       const element = timeline.deselectAll();
-      chai.expect(element.selectionChanged).equal(true);
-      chai.expect(element.selected.length).equal(0);
+      expect(element.selectionChanged).toBe(true);
+      expect(element.selected.length).toBe(0);
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
-            chai.expect(keyframe.selected).equal(false);
+            expect(keyframe.selected).toBe(false);
           });
         }
       });
@@ -294,7 +301,7 @@ describe('Timeline', () => {
       // Select all
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             keyframe.selectable = true;
@@ -306,26 +313,26 @@ describe('Timeline', () => {
 
       // select one will deselect other
       const rowToSelect = model.rows[1];
-      chai.expect(!!rowToSelect.keyframes).equal(true);
+      expect(!!rowToSelect.keyframes).toBe(true);
       if (!rowToSelect.keyframes) {
         return;
       }
       // toggle selection
       const toSelect = rowToSelect.keyframes[0];
       const element = timeline.select(toSelect);
-      chai.expect(element.selectionChanged).equal(true);
-      chai.expect(element.selected.length).equal(1);
-      chai.expect(element.changed.length).equal(expectedChanged - 1);
+      expect(element.selectionChanged).toBe(true);
+      expect(element.selected.length).toBe(1);
+      expect(element.changed.length).toBe(expectedChanged - 1);
 
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             if (toSelect == keyframe) {
-              chai.expect(keyframe.selected).equal(true);
+              expect(keyframe.selected).toBe(true);
             } else {
-              chai.expect(keyframe.selected).equal(false);
+              expect(keyframe.selected).toBe(false);
             }
           });
         }
@@ -338,7 +345,7 @@ describe('Timeline', () => {
       // Select all
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             keyframe.selectable = true;
@@ -349,7 +356,7 @@ describe('Timeline', () => {
       });
 
       const rowToSelect = model.rows[1];
-      chai.expect(!!rowToSelect.keyframes).equal(true);
+      expect(!!rowToSelect.keyframes).toBe(true);
       if (!rowToSelect.keyframes) {
         return;
       }
@@ -358,18 +365,18 @@ describe('Timeline', () => {
 
       // item is selected, should be reverted
       const element = timeline.select(toSelect, TimelineSelectionMode.Revert);
-      chai.expect(element.selectionChanged).equal(true);
-      chai.expect(element.selected.length).equal(totalKeyframes - 1);
-      chai.expect(element.changed.length).equal(1);
+      expect(element.selectionChanged).toBe(true);
+      expect(element.selected.length).toBe(totalKeyframes - 1);
+      expect(element.changed.length).toBe(1);
 
       model.rows.forEach((row: TimelineRow) => {
-        chai.expect((row.keyframes?.length || 0) > 0).equal(true);
+        expect((row.keyframes?.length || 0) > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             if (toSelect == keyframe) {
-              chai.expect(keyframe.selected).equal(false);
+              expect(keyframe.selected).toBe(false);
             } else {
-              chai.expect(keyframe.selected).equal(true);
+              expect(keyframe.selected).toBe(true);
             }
           });
         }
@@ -381,7 +388,7 @@ describe('Timeline', () => {
       // Deselect all
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             keyframe.selectable = true;
@@ -392,30 +399,30 @@ describe('Timeline', () => {
 
       // select one will deselect other
       const rowToSelect = model.rows[1];
-      chai.expect(!!rowToSelect.keyframes).equal(true);
+      expect(!!rowToSelect.keyframes).toBe(true);
       if (!rowToSelect.keyframes) {
         return;
       }
       const element = timeline.select(rowToSelect.keyframes);
-      chai.expect(element.selectionChanged).equal(true);
-      chai.expect(element.selected.length).equal(rowToSelect.keyframes.length);
-      chai.expect(element.changed.length).equal(3);
+      expect(element.selectionChanged).toBe(true);
+      expect(element.selected.length).toBe(rowToSelect.keyframes.length);
+      expect(element.changed.length).toBe(3);
 
       model.rows.forEach((row: TimelineRow) => {
         if (rowToSelect === row) {
           const len = row?.keyframes?.length || 0;
-          chai.expect(len > 0).equal(true);
+          expect(len > 0).toBe(true);
           if (rowToSelect.keyframes) {
             rowToSelect.keyframes.forEach((keyframe: TimelineKeyframe) => {
-              chai.expect(keyframe.selected).equal(true);
+              expect(keyframe.selected).toBe(true);
             });
           }
         } else {
           const len = row?.keyframes?.length || 0;
-          chai.expect(len > 0).equal(true);
+          expect(len > 0).toBe(true);
           if (row.keyframes) {
             row.keyframes.forEach((keyframe: TimelineKeyframe) => {
-              chai.expect(keyframe.selected).equal(false);
+              expect(keyframe.selected).toBe(false);
             });
           }
         }
@@ -427,7 +434,7 @@ describe('Timeline', () => {
       // Deselect all
       model.rows.forEach((row: TimelineRow) => {
         const len = row?.keyframes?.length || 0;
-        chai.expect(len > 0).equal(true);
+        expect(len > 0).toBe(true);
         if (row.keyframes) {
           row.keyframes.forEach((keyframe: TimelineKeyframe) => {
             keyframe.selected = false;
@@ -437,35 +444,35 @@ describe('Timeline', () => {
 
       // select one row (array of the keyframes)
       const rowToSelect = model.rows[1];
-      chai.expect(!!rowToSelect.keyframes).equal(true);
+      expect(!!rowToSelect.keyframes).toBe(true);
       if (!rowToSelect.keyframes) {
         return;
       }
       let results = timeline.select(rowToSelect.keyframes);
-      chai.expect(results.selectionChanged).equal(true);
-      chai.expect(results.selected.length).equal(rowToSelect.keyframes?.length);
-      chai.expect(results.changed.length).equal(rowToSelect.keyframes?.length);
+      expect(results.selectionChanged).toBe(true);
+      expect(results.selected.length).toBe(rowToSelect.keyframes?.length);
+      expect(results.changed.length).toBe(rowToSelect.keyframes?.length);
 
       // (array of the keyframes)
       const rowToSelect2 = model.rows[2];
       results = timeline.select(rowToSelect2?.keyframes || [], TimelineSelectionMode.Append);
-      chai.expect(results.selectionChanged).equal(true);
-      chai.expect(results.selected.length).equal((rowToSelect?.keyframes?.length || 0) + (rowToSelect2?.keyframes?.length || 0));
-      chai.expect(results.changed.length).equal(rowToSelect2?.keyframes?.length);
+      expect(results.selectionChanged).toBe(true);
+      expect(results.selected.length).toBe((rowToSelect?.keyframes?.length || 0) + (rowToSelect2?.keyframes?.length || 0));
+      expect(results.changed.length).toBe(rowToSelect2?.keyframes?.length);
 
       model.rows.forEach((row: TimelineRow) => {
         if (rowToSelect === row || rowToSelect2 === row) {
-          chai.expect((rowToSelect.keyframes?.length || 0) > 0).equal(true);
+          expect((rowToSelect.keyframes?.length || 0) > 0).toBe(true);
           if (rowToSelect.keyframes) {
             rowToSelect.keyframes.forEach((keyframe: TimelineKeyframe) => {
-              chai.expect(keyframe.selected).equal(true);
+              expect(keyframe.selected).toBe(true);
             });
           }
         } else {
-          chai.expect((row.keyframes?.length || 0) > 0).equal(true);
+          expect((row.keyframes?.length || 0) > 0).toBe(true);
           if (row.keyframes) {
             row.keyframes.forEach((keyframe: TimelineKeyframe) => {
-              chai.expect(keyframe.selected).equal(false);
+              expect(keyframe.selected).toBe(false);
             });
           }
         }
@@ -481,13 +488,13 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.valToPx(0)).equal(0);
-      chai.expect(timeline.valToPx(100)).equal(50);
-      chai.expect(timeline.valToPx(200)).equal(100);
+      expect(timeline.valToPx(0)).toBe(0);
+      expect(timeline.valToPx(100)).toBe(50);
+      expect(timeline.valToPx(200)).toBe(100);
 
-      chai.expect(timeline.pxToVal(0)).equal(0);
-      chai.expect(timeline.pxToVal(50)).equal(100);
-      chai.expect(timeline.pxToVal(100)).equal(200);
+      expect(timeline.pxToVal(0)).toBe(0);
+      expect(timeline.pxToVal(50)).toBe(100);
+      expect(timeline.pxToVal(100)).toBe(200);
     });
     it('Coordinates. min is negative', () => {
       const timeline = new Timeline();
@@ -498,17 +505,17 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.valToPx(-100)).equal(0);
-      chai.expect(timeline.valToPx(-50)).equal(25);
-      chai.expect(timeline.valToPx(0)).equal(50);
-      chai.expect(timeline.valToPx(50)).equal(75);
-      chai.expect(timeline.valToPx(100)).equal(100);
+      expect(timeline.valToPx(-100)).toBe(0);
+      expect(timeline.valToPx(-50)).toBe(25);
+      expect(timeline.valToPx(0)).toBe(50);
+      expect(timeline.valToPx(50)).toBe(75);
+      expect(timeline.valToPx(100)).toBe(100);
 
-      chai.expect(timeline.pxToVal(0)).equal(-100);
-      chai.expect(timeline.pxToVal(25)).equal(-50);
-      chai.expect(timeline.pxToVal(50)).equal(0);
-      chai.expect(timeline.pxToVal(75)).equal(50);
-      chai.expect(timeline.pxToVal(100)).equal(100);
+      expect(timeline.pxToVal(0)).toBe(-100);
+      expect(timeline.pxToVal(25)).toBe(-50);
+      expect(timeline.pxToVal(50)).toBe(0);
+      expect(timeline.pxToVal(75)).toBe(50);
+      expect(timeline.pxToVal(100)).toBe(100);
     });
     it('Coordinates. min is positive', () => {
       const timeline = new Timeline();
@@ -519,11 +526,11 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.valToPx(100)).equal(0);
-      chai.expect(timeline.valToPx(150)).equal(25);
+      expect(timeline.valToPx(100)).toBe(0);
+      expect(timeline.valToPx(150)).toBe(25);
 
-      chai.expect(timeline.pxToVal(0)).equal(100);
-      chai.expect(timeline.pxToVal(25)).equal(150);
+      expect(timeline.pxToVal(0)).toBe(100);
+      expect(timeline.pxToVal(25)).toBe(150);
     });
     it('Zoom is respected', () => {
       const timeline = new Timeline();
@@ -533,17 +540,17 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.valToPx(0)).equal(0);
-      chai.expect(timeline.valToPx(100)).equal(50);
-      chai.expect(timeline.valToPx(200)).equal(100);
+      expect(timeline.valToPx(0)).toBe(0);
+      expect(timeline.valToPx(100)).toBe(50);
+      expect(timeline.valToPx(200)).toBe(100);
       timeline._setZoom(2);
-      chai.expect(timeline.valToPx(0)).equal(0);
-      chai.expect(timeline.valToPx(100)).equal(25);
-      chai.expect(timeline.valToPx(200)).equal(50);
+      expect(timeline.valToPx(0)).toBe(0);
+      expect(timeline.valToPx(100)).toBe(25);
+      expect(timeline.valToPx(200)).toBe(50);
 
-      chai.expect(timeline.pxToVal(0)).equal(0);
-      chai.expect(timeline.pxToVal(25)).equal(100);
-      chai.expect(timeline.pxToVal(50)).equal(200);
+      expect(timeline.pxToVal(0)).toBe(0);
+      expect(timeline.pxToVal(25)).toBe(100);
+      expect(timeline.pxToVal(50)).toBe(200);
     });
   });
   describe('Snapping', () => {
@@ -556,11 +563,11 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.snapVal(0)).equal(0);
-      chai.expect(timeline.snapVal(10)).equal(0);
-      chai.expect(timeline.snapVal(26)).equal(25);
-      chai.expect(timeline.snapVal(48)).equal(50);
-      chai.expect(timeline.snapVal(58)).equal(50);
+      expect(timeline.snapVal(0)).toBe(0);
+      expect(timeline.snapVal(10)).toBe(0);
+      expect(timeline.snapVal(26)).toBe(25);
+      expect(timeline.snapVal(48)).toBe(50);
+      expect(timeline.snapVal(58)).toBe(50);
     });
     it('Snapping. min is defined', () => {
       const timeline = new Timeline();
@@ -572,14 +579,14 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.snapVal(0)).equal(5);
-      chai.expect(timeline.snapVal(10)).equal(5);
-      chai.expect(timeline.snapVal(26)).equal(30);
-      chai.expect(timeline.snapVal(48)).equal(55);
-      chai.expect(timeline.snapVal(58)).equal(55);
+      expect(timeline.snapVal(0)).toBe(5);
+      expect(timeline.snapVal(10)).toBe(5);
+      expect(timeline.snapVal(26)).toBe(30);
+      expect(timeline.snapVal(48)).toBe(55);
+      expect(timeline.snapVal(58)).toBe(55);
 
       // Don't overlap the limit.
-      chai.expect(timeline.snapVal(-100)).equal(5);
+      expect(timeline.snapVal(-100)).toBe(5);
     });
     it('Snapping. negative min is defined', () => {
       const timeline = new Timeline();
@@ -591,38 +598,38 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.snapVal(0)).equal(-5);
-      chai.expect(timeline.snapVal(10)).equal(-5);
-      chai.expect(timeline.snapVal(26)).equal(20);
-      chai.expect(timeline.snapVal(48)).equal(45);
-      chai.expect(timeline.snapVal(58)).equal(45);
+      expect(timeline.snapVal(0)).toBe(-5);
+      expect(timeline.snapVal(10)).toBe(-5);
+      expect(timeline.snapVal(26)).toBe(20);
+      expect(timeline.snapVal(48)).toBe(45);
+      expect(timeline.snapVal(58)).toBe(45);
 
-      chai.expect(timeline.snapVal(-1)).equal(-5);
-      chai.expect(timeline.snapVal(-10)).equal(-5);
-      chai.expect(timeline.snapVal(-26)).equal(-30);
-      chai.expect(timeline.snapVal(-48)).equal(-55);
-      chai.expect(timeline.snapVal(-58)).equal(-55);
+      expect(timeline.snapVal(-1)).toBe(-5);
+      expect(timeline.snapVal(-10)).toBe(-5);
+      expect(timeline.snapVal(-26)).toBe(-30);
+      expect(timeline.snapVal(-48)).toBe(-55);
+      expect(timeline.snapVal(-58)).toBe(-55);
 
       // Don't overlap the limit.
-      chai.expect(timeline.snapVal(-100)).equal(-55);
+      expect(timeline.snapVal(-100)).toBe(-55);
     });
     it('TimelineUtils.isNumber', () => {
-      chai.expect(TimelineUtils.isNumber(0)).equal(true);
-      chai.expect(TimelineUtils.isNumber(-1)).equal(true);
-      chai.expect(TimelineUtils.isNumber(1)).equal(true);
-      chai.expect(TimelineUtils.isNumber(null)).equal(false);
-      chai.expect(TimelineUtils.isNumber(undefined)).equal(false);
-      chai.expect(TimelineUtils.isNumber(Number.NEGATIVE_INFINITY)).equal(false);
-      chai.expect(TimelineUtils.isNumber(Number.NaN)).equal(false);
+      expect(TimelineUtils.isNumber(0)).toBe(true);
+      expect(TimelineUtils.isNumber(-1)).toBe(true);
+      expect(TimelineUtils.isNumber(1)).toBe(true);
+      expect(TimelineUtils.isNumber(null)).toBe(false);
+      expect(TimelineUtils.isNumber(undefined)).toBe(false);
+      expect(TimelineUtils.isNumber(Number.NEGATIVE_INFINITY)).toBe(false);
+      expect(TimelineUtils.isNumber(Number.NaN)).toBe(false);
     });
     it('TimelineUtils.keepInBounds', () => {
-      chai.expect(TimelineUtils.keepInBounds(0, -1, 2)).equal(0);
-      chai.expect(TimelineUtils.keepInBounds(0, 1, 2)).equal(1);
-      chai.expect(TimelineUtils.keepInBounds(0, 1, null)).equal(1);
-      chai.expect(TimelineUtils.keepInBounds(10, null, 2)).equal(2);
-      chai.expect(TimelineUtils.keepInBounds(-10, -1, 2)).equal(-1);
-      chai.expect(TimelineUtils.keepInBounds(-10, 2, 2)).equal(2);
-      chai.expect(TimelineUtils.keepInBounds(10, 1, 2)).equal(2);
+      expect(TimelineUtils.keepInBounds(0, -1, 2)).toBe(0);
+      expect(TimelineUtils.keepInBounds(0, 1, 2)).toBe(1);
+      expect(TimelineUtils.keepInBounds(0, 1, null)).toBe(1);
+      expect(TimelineUtils.keepInBounds(10, null, 2)).toBe(2);
+      expect(TimelineUtils.keepInBounds(-10, -1, 2)).toBe(-1);
+      expect(TimelineUtils.keepInBounds(-10, 2, 2)).toBe(2);
+      expect(TimelineUtils.keepInBounds(10, 1, 2)).toBe(2);
     });
     it('TimelineUtils.cutBounds', () => {
       const cutInformation = new Timeline()._cutBoundsWhenOverlap(
@@ -644,13 +651,13 @@ describe('Timeline', () => {
         10,
         50,
       );
-      chai.assert(cutInformation);
-      const rect = cutInformation.rect;
-      chai.assert(rect);
-      chai.expect(rect.x).equal(10);
-      chai.expect(rect.y).equal(10);
-      chai.expect(rect.width).equal(90);
-      chai.expect(rect.height).equal(90);
+      expect(cutInformation);
+      const rect = cutInformation?.rect;
+      expect(rect);
+      expect(rect?.x).toBe(10);
+      expect(rect?.y).toBe(10);
+      expect(rect?.width).toBe(90);
+      expect(rect?.height).toBe(90);
     });
 
     it('Snapping. negative min (-25) is defined', () => {
@@ -663,12 +670,12 @@ describe('Timeline', () => {
         zoom: 1,
       } as TimelineOptions);
 
-      chai.expect(timeline.snapVal(-1)).equal(0);
-      chai.expect(timeline.snapVal(-10)).equal(0);
-      chai.expect(timeline.snapVal(10)).equal(0);
-      chai.expect(timeline.snapVal(26)).equal(25);
-      chai.expect(timeline.snapVal(50)).equal(50);
-      chai.expect(timeline.snapVal(-58)).equal(-25);
+      expect(timeline.snapVal(-1) === 0).toBeTruthy();
+      expect(timeline.snapVal(-10) === 0).toBeTruthy();
+      expect(timeline.snapVal(10) === 0).toBeTruthy();
+      expect(timeline.snapVal(26)).toBe(25);
+      expect(timeline.snapVal(50)).toBe(50);
+      expect(timeline.snapVal(-58)).toBe(-25);
     });
   });
   describe('Move Keyframes', () => {
@@ -683,12 +690,12 @@ describe('Timeline', () => {
       timeline._model = model;
       const move = -50;
       const row = model.rows[0];
-      chai.expect(!!row).equal(true);
+      expect(!!row).toBe(true);
       if (!row) {
         return;
       }
       const keyframes = row.keyframes;
-      chai.expect(!!keyframes).equal(true);
+      expect(!!keyframes).toBe(true);
       if (!keyframes) {
         return;
       }
@@ -703,9 +710,9 @@ describe('Timeline', () => {
         } as TimelineElementDragState,
       ]);
 
-      chai.expect(movedOffset).equal(move);
-      chai.expect(keyframes[0]?.val).equal(item1 + move);
-      chai.expect(keyframes[1]?.val).equal(item2 + move);
+      expect(movedOffset).toBe(move);
+      expect(keyframes[0]?.val).toBe(item1 + move);
+      expect(keyframes[1]?.val).toBe(item2 + move);
     });
     it('move right', () => {
       const timeline = new Timeline();
@@ -718,12 +725,12 @@ describe('Timeline', () => {
       timeline._model = model;
       const move = 100;
       const row = model.rows[0];
-      chai.expect(!!row).equal(true);
+      expect(!!row).toBe(true);
       if (!row) {
         return;
       }
       const keyframes = row.keyframes;
-      chai.expect(!!keyframes).equal(true);
+      expect(!!keyframes).toBe(true);
       if (!keyframes) {
         return;
       }
@@ -738,9 +745,9 @@ describe('Timeline', () => {
         } as TimelineElementDragState,
       ]);
 
-      chai.expect(movedOffset).equal(move);
-      chai.expect(keyframes[0]?.val).equal(item1 + move);
-      chai.expect(keyframes[1]?.val).equal(item2 + move);
+      expect(movedOffset).toBe(move);
+      expect(keyframes[0]?.val).toBe(item1 + move);
+      expect(keyframes[1]?.val).toBe(item2 + move);
     });
     it('move left limited by min', () => {
       const timeline = new Timeline();
@@ -758,9 +765,9 @@ describe('Timeline', () => {
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
-      chai.expect(movedOffset).equal(move / 2);
-      chai.expect(elementsToMove[0].keyframe?.val).equal(0);
-      chai.expect(elementsToMove[1].keyframe?.val).equal(25);
+      expect(movedOffset).toBe(move / 2);
+      expect(elementsToMove[0].keyframe?.val).toBe(0);
+      expect(elementsToMove[1].keyframe?.val).toBe(25);
     });
 
     it('move right limited by max', () => {
@@ -779,9 +786,9 @@ describe('Timeline', () => {
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
-      chai.expect(movedOffset).equal(move / 2);
-      chai.expect(elementsToMove[0].keyframe?.val).equal(item1 + 50);
-      chai.expect(elementsToMove[1].keyframe?.val).equal(item2 + 50);
+      expect(movedOffset).toBe(move / 2);
+      expect(elementsToMove[0].keyframe?.val).toBe(item1 + 50);
+      expect(elementsToMove[1].keyframe?.val).toBe(item2 + 50);
     });
     it('move right limited by max negative', () => {
       const timeline = new Timeline();
@@ -799,9 +806,9 @@ describe('Timeline', () => {
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
-      chai.expect(movedOffset).equal(25);
-      chai.expect(elementsToMove[0].keyframe?.val).equal(item1 + 25);
-      chai.expect(elementsToMove[1].keyframe?.val).equal(item2 + 25);
+      expect(movedOffset).toBe(25);
+      expect(elementsToMove[0].keyframe?.val).toBe(item1 + 25);
+      expect(elementsToMove[1].keyframe?.val).toBe(item2 + 25);
     });
     it('move right limited by max negative when other row out of the bounds', () => {
       const timeline = new Timeline();
@@ -829,11 +836,11 @@ describe('Timeline', () => {
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
       const moved = move / 2;
-      chai.expect(movedOffset).equal(moved);
-      chai.expect(elementsToMove[0].keyframe?.val).equal(100 + moved);
-      chai.expect(elementsToMove[1].keyframe?.val).equal(400 + moved);
-      chai.expect(elementsToMove[2].keyframe?.val).equal(200 + moved);
-      chai.expect(elementsToMove[3].keyframe?.val).equal(300 + moved);
+      expect(movedOffset).toBe(moved);
+      expect(elementsToMove[0].keyframe?.val).toBe(100 + moved);
+      expect(elementsToMove[1].keyframe?.val).toBe(400 + moved);
+      expect(elementsToMove[2].keyframe?.val).toBe(200 + moved);
+      expect(elementsToMove[3].keyframe?.val).toBe(300 + moved);
     });
     it('move left limited by min negative', () => {
       const timeline = new Timeline();
@@ -851,9 +858,9 @@ describe('Timeline', () => {
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
-      chai.expect(movedOffset).equal(move / 2);
-      chai.expect(elementsToMove[0].keyframe?.val).equal(item1 - 50);
-      chai.expect(elementsToMove[1].keyframe?.val).equal(item2 - 50);
+      expect(movedOffset).toBe(move / 2);
+      expect(elementsToMove[0].keyframe?.val).toBe(item1 - 50);
+      expect(elementsToMove[1].keyframe?.val).toBe(item2 - 50);
     });
     it('move left only one keyframe is limited', () => {
       const timeline = new Timeline();
@@ -871,9 +878,9 @@ describe('Timeline', () => {
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
 
-      chai.expect(movedOffset).equal(move / 2);
-      chai.expect(elementsToMove[0].keyframe?.val).equal(25 + 50);
-      chai.expect(elementsToMove[1].keyframe?.val).equal(50 + 50);
+      expect(movedOffset).toBe(move / 2);
+      expect(elementsToMove[0].keyframe?.val).toBe(25 + 50);
+      expect(elementsToMove[1].keyframe?.val).toBe(50 + 50);
     });
     it('move left only one keyframe has min bounds', () => {
       const timeline = new Timeline();
@@ -890,9 +897,9 @@ describe('Timeline', () => {
         } as TimelineElementDragState,
       ];
       const movedOffset = timeline._moveElements(move, elementsToMove);
-      chai.expect(movedOffset).equal(-20);
-      chai.expect(elementsToMove[0].keyframe?.val).equal(5);
-      chai.expect(elementsToMove[1].keyframe?.val).equal(30);
+      expect(movedOffset).toBe(-20);
+      expect(elementsToMove[0].keyframe?.val).toBe(5);
+      expect(elementsToMove[1].keyframe?.val).toBe(30);
     });
   });
 });

+ 0 - 47
tests/unittests.html

@@ -1,47 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <title>Mocha Tests</title>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
-  </head>
-
-  <body>
-    <div>
-      <a href="../index.html">Back</a>
-      <p>Build tests using the npm 'build' command before executing tests. Results:</p>
-    </div>
-    <div id="mocha"></div>
-
-    <script src="https://unpkg.com/[email protected]/chai.js"></script>
-    <script src="https://unpkg.com/[email protected]/mocha.js"></script>
-    <script src="../lib/animation-timeline.js"></script>
-    <script>
-      if (!window.exports) {
-        window.exports = {};
-      }
-    </script>
-    <script>
-      if (!window.require) {
-        window.require = function (moduleName) {
-          if (moduleName.indexOf('assert') > 0) {
-            return exports;
-          } else {
-            return timelineModule;
-          }
-        };
-      }
-    </script>
-    <script class="mocha-init">
-      mocha.setup('bdd');
-      mocha.checkLeaks();
-    </script>
-    <script src="../lib/tests/styleTests.test.js"></script>
-    <script src="../lib/tests/timelineTests.test.js"></script>
-    <script src="../lib/tests/settingsTests.test.js"></script>
-    <script class="mocha-exec">
-      mocha.run();
-    </script>
-  </body>
-</html>

+ 0 - 15
tsconfig.tests.json

@@ -1,15 +0,0 @@
-{
-  "compilerOptions": {
-    "module": "CommonJS",
-    "outDir": "./lib/tests",
-    "lib": ["es2015", "dom"],
-    "target": "es5",
-    "allowJs": false,
-    "inlineSourceMap": true,
-    "strict": true,
-    "declaration": false,
-    "forceConsistentCasingInFileNames": true
-  },
-  "include": ["./tests/*"],
-  "exclude": ["node_modules", "lib", "tests/js", "src", "src/*", "dist", "*.json", "*.js"]
-}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно