grafana/public/app/features/explore/TraceView/components/Tween.test.ts
Andre Pereira afd39c18ba
Explore: Refactor trace view and move to core (#61938)
* Move TraceView to core grafana

* Remove unused code

* yarn install

* Remove jaeger-ui-components from CODEOWNERS and other tools

* Type fixes

* yarn install

* Remove mock that we no longer need

* Fix merge conflicts

* Re-add Apache license for trace view components

* Use an exclamation-circle instead of triangle to denote errors

* Remove eslint disables and update betterer results instead
2023-01-27 14:13:17 +00:00

197 lines
6.7 KiB
TypeScript

// Copyright (c) 2017 Uber Technologies, Inc.
//
// Licensed 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.
import Tween, { TweenState } from './Tween';
describe('Tween', () => {
const oldNow = Date.now;
const nowFn = jest.fn();
const oldSetTimeout = window.setTimeout;
const setTimeoutFn = jest.fn();
const oldRaf = window.requestAnimationFrame;
const rafFn = jest.fn();
const baseOptions = { duration: 10, from: 0, to: 1 };
jest.useFakeTimers();
jest.spyOn(global, 'setTimeout');
Date.now = nowFn;
window.requestAnimationFrame = rafFn;
beforeEach(() => {
nowFn.mockReset();
nowFn.mockReturnValue(0);
setTimeoutFn.mockReset();
rafFn.mockReset();
});
afterAll(() => {
Date.now = oldNow;
window.setTimeout = oldSetTimeout;
window.requestAnimationFrame = oldRaf;
});
describe('ctor', () => {
it('set startTime to the current time', () => {
const n = Math.random();
nowFn.mockReturnValue(n);
const tween = new Tween(baseOptions);
expect(tween.startTime).toBe(n);
});
it('adds delay to the startTime', () => {
const n = Math.random();
nowFn.mockReturnValue(n);
const tween = new Tween({ ...baseOptions, delay: 10 });
expect(tween.startTime).toBe(n + 10);
});
describe('with callbacks', () => {
it('schedules setTimeout if there is a delay', () => {
const delay = 10;
const tween = new Tween({ ...baseOptions, delay, onUpdate: jest.fn() });
expect(setTimeout).lastCalledWith(tween._frameCallback, delay);
});
it('schedules animation frame if there is not a delay', () => {
const tween = new Tween({ ...baseOptions, onUpdate: jest.fn() });
expect(rafFn).lastCalledWith(tween._frameCallback);
});
});
});
describe('getCurrent()', () => {
it('returns `{done: false, value: from}` when time is before the delay is finished', () => {
const tween = new Tween({ ...baseOptions, delay: 1 });
const current = tween.getCurrent();
expect(current).toEqual({ done: false, value: baseOptions.from });
});
describe('in progress tweens', () => {
it('returns `{done: false...`}', () => {
const tween = new Tween(baseOptions);
nowFn.mockReturnValue(1);
const current = tween.getCurrent();
expect(current.done).toBe(false);
expect(nowFn()).toBeLessThan(tween.startTime + tween.duration);
expect(nowFn()).toBeGreaterThan(tween.startTime);
});
it('progresses `{..., value} as time progresses', () => {
const tween = new Tween(baseOptions);
let lastValue = tween.getCurrent().value;
for (let i = 1; i < baseOptions.duration; i++) {
nowFn.mockReturnValue(i);
const { done, value } = tween.getCurrent();
expect(done).toBe(false);
expect(value).toBeGreaterThan(lastValue);
lastValue = value;
}
});
});
it('returns `{done: true, value: to}` when the time is past the duration', () => {
const tween = new Tween(baseOptions);
nowFn.mockReturnValue(baseOptions.duration);
const current = tween.getCurrent();
expect(current).toEqual({ done: true, value: baseOptions.to });
});
});
describe('_frameCallback', () => {
it('freezes the callback argument', () => {
let current: TweenState | undefined;
const fn = jest.fn((_current) => {
current = _current;
});
const tween = new Tween({ ...baseOptions, onUpdate: fn });
tween._frameCallback();
expect(current).toBeDefined();
const copy = { ...current };
try {
current!.done = !current!.done;
// eslint-disable-next-line no-empty
} catch (_) {}
expect(current).toEqual(copy);
});
it('calls onUpdate if there is an onUpdate callback', () => {
const fn = jest.fn();
const tween = new Tween({ ...baseOptions, onUpdate: fn });
tween._frameCallback();
const current = tween.getCurrent();
expect(current).toBeDefined();
expect(fn).lastCalledWith(current);
});
it('does not call onComplete if there is an onComplete callback and the tween is not complete', () => {
const fn = jest.fn();
const tween = new Tween({ ...baseOptions, onComplete: fn });
tween._frameCallback();
expect(fn.mock.calls.length).toBe(0);
});
it('calls onComplete if there is an onComplete callback and the tween is complete', () => {
const fn = jest.fn();
const tween = new Tween({ ...baseOptions, onComplete: fn });
nowFn.mockReturnValue(nowFn() + baseOptions.duration);
tween._frameCallback();
const current = tween.getCurrent();
expect(fn.mock.calls).toEqual([[current]]);
expect(current.done).toBe(true);
});
it('schedules an animatinon frame if the tween is not complete', () => {
expect(rafFn.mock.calls.length).toBe(0);
const tween = new Tween({ ...baseOptions, onUpdate: () => {} });
nowFn.mockReturnValue(nowFn() + 0.5 * baseOptions.duration);
rafFn.mockReset();
tween._frameCallback();
expect(rafFn.mock.calls).toEqual([[tween._frameCallback]]);
});
});
describe('cancel()', () => {
it('cancels scheduled timeouts or animation frames', () => {
const oldClearTimeout = window.clearTimeout;
const oldCancelRaf = window.cancelAnimationFrame;
const clearFn = jest.fn();
window.clearTimeout = clearFn;
const cancelFn = jest.fn();
window.cancelAnimationFrame = cancelFn;
const tween = new Tween(baseOptions);
const id = 1;
tween.timeoutID = id;
tween.requestID = id;
tween.cancel();
expect(clearFn.mock.calls).toEqual([[id]]);
expect(cancelFn.mock.calls).toEqual([[id]]);
expect(tween.timeoutID).toBe(undefined);
expect(tween.requestID).toBe(undefined);
window.clearTimeout = oldClearTimeout;
window.cancelAnimationFrame = oldCancelRaf;
});
it('releases references to callbacks', () => {
const tween = new Tween({ ...baseOptions, onComplete: () => {}, onUpdate: () => {} });
tween.cancel();
expect(tween.onComplete).toBe(undefined);
expect(tween.onUpdate).toBe(undefined);
});
});
});