Skip to content

Commit

Permalink
moving all
Browse files Browse the repository at this point in the history
  • Loading branch information
vlio20 committed Dec 6, 2024
1 parent 2f8f5fb commit 52f9f22
Show file tree
Hide file tree
Showing 37 changed files with 569 additions and 815 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"scripts": {
"test:full": "npm run clean && tsc -p tsconfig.test.json --noEmit && npm run lint && node --test --experimental-test-coverage && npm run test:mutation",
"test:unit": "npm run clean && tsc --noEmit && npm run lint && node --test",
"test": "tsx --test $(find src -type f -name 'cancel-previous.spec.ts')",
"test": "tsx --test $(find src -type f -name '*.spec.ts')",
"test:mutation": "stryker run",
"lint": "eslint ./src --ext .ts --quiet",
"lint:fix": "eslint ./src --ext .ts --fix",
Expand Down
7 changes: 4 additions & 3 deletions src/cancel-previous/cancel-previous.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ describe('cancelPrevious', () => {
const nonValidCancelPrevious: any = cancelPrevious<T>();

class T {
@nonValidCancelPrevious boo: string;
@nonValidCancelPrevious
boo: string;
}
}, '@cancelPrevious is applicable only on a methods.');
}, Error('@cancelPrevious is applicable only on a methods.'));
});

it('should cancel prev invocation', (ctx, done) => {
Expand Down Expand Up @@ -44,7 +45,7 @@ describe('cancelPrevious', () => {
return;
}

throw new Error('should\'t get here');
throw new Error('shouldn\'t get here');
});
};

Expand Down
2 changes: 1 addition & 1 deletion src/cancel-previous/cancel-previous.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function cancelPrevious<T = any>(): CancelPreviousable<T> {
propertyName: keyof T,
descriptor: TypedPropertyDescriptor<Method<Promise<any>>>,
): TypedPropertyDescriptor<Method<Promise<any>>> => {
if (descriptor.value) {
if (descriptor && descriptor.value) {
descriptor.value = cancelPreviousify(descriptor.value);

return descriptor;
Expand Down
34 changes: 18 additions & 16 deletions src/common/data-stractures/queue.spec.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,49 @@
import { Queue } from './queue';
import { describe, it } from 'node:test';
import assert from 'node:assert';

describe('Queue', () => {
it('should initialize with size 0', () => {
const queue = new Queue<number>();
expect(queue.getSize()).toBe(0);
expect(queue.isEmpty()).toBe(true);
assert.strictEqual(queue.getSize(), 0);
assert.strictEqual(queue.isEmpty(), true);
});

it('should enqueue items and update size', () => {
const queue = new Queue<number>();
queue.enqueue(1);
expect(queue.getSize()).toBe(1);
expect(queue.isEmpty()).toBe(false);
assert.strictEqual(queue.getSize(), 1);
assert.strictEqual(queue.isEmpty(), false);
queue.enqueue(2);
expect(queue.getSize()).toBe(2);
assert.strictEqual(queue.getSize(), 2);
});

it('should dequeue items in the correct order', () => {
const queue = new Queue<number>();
queue.enqueue(1);
queue.enqueue(2);
expect(queue.dequeue()).toBe(1);
expect(queue.getSize()).toBe(1);
expect(queue.dequeue()).toBe(2);
expect(queue.getSize()).toBe(0);
expect(queue.isEmpty()).toBe(true);
assert.strictEqual(queue.dequeue(), 1);
assert.strictEqual(queue.getSize(), 1);
assert.strictEqual(queue.dequeue(), 2);
assert.strictEqual(queue.getSize(), 0);
assert.strictEqual(queue.isEmpty(), true);
});

it('should return null when dequeue is called on an empty queue', () => {
const queue = new Queue<number>();
expect(queue.dequeue()).toBeNull();
assert.strictEqual(queue.dequeue(), null);
});

it('should handle enqueue and dequeue operations correctly', () => {
const queue = new Queue<number>();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
expect(queue.dequeue()).toBe(1);
assert.strictEqual(queue.dequeue(), 1);
queue.enqueue(4);
expect(queue.dequeue()).toBe(2);
expect(queue.dequeue()).toBe(3);
expect(queue.dequeue()).toBe(4);
expect(queue.isEmpty()).toBe(true);
assert.strictEqual(queue.dequeue(), 2);
assert.strictEqual(queue.dequeue(), 3);
assert.strictEqual(queue.dequeue(), 4);
assert.strictEqual(queue.isEmpty(), true);
});
});
58 changes: 22 additions & 36 deletions src/common/tesk-exec/task-exec.spec.ts
Original file line number Diff line number Diff line change
@@ -1,90 +1,76 @@
import { TaskExec } from './task-exec';
import { sleep } from '../test-utils';
import { describe, it, mock } from 'node:test';
import assert from 'node:assert';

describe('utils', () => {
it('should verify task executed in time - A:40, B:20 -> B, A', async () => {
const runner = new TaskExec();
let val = '';
const funA = jest.fn().mockImplementation(() => {
val += 'A';
});
const funB = jest.fn().mockImplementation(() => {
val += 'B';
});
const funA = () => { val += 'A'; };
const funB = () => { val += 'B'; };

runner.exec(funA, 100);

await sleep(20);

expect(funA).not.toHaveBeenCalled();
assert.strictEqual(val, '');
runner.exec(funB, 40);

await sleep(20);

expect(funA).not.toHaveBeenCalled();
expect(funB).not.toHaveBeenCalled();
assert.strictEqual(val, '');

await sleep(40);

expect(funA).not.toHaveBeenCalled();
expect(funB).toHaveBeenCalledTimes(1);
assert.strictEqual(val, 'B');

await sleep(100);

expect(funA).toHaveBeenCalledTimes(1);
expect(funB).toHaveBeenCalledTimes(1);
expect(val).toBe('BA');
assert.strictEqual(val, 'BA');
});

it('should verify task executed in time - A:20, B:40 -> A, B', async () => {
const runner = new TaskExec();
let val = '';
const funA = jest.fn().mockImplementation(() => {
val += 'A';
});
const funB = jest.fn().mockImplementation(() => {
val += 'B';
});
const funA = () => { val += 'A'; };
const funB = () => { val += 'B'; };

runner.exec(funA, 50);
runner.exec(funB, 100);

await sleep(20);

expect(funA).not.toHaveBeenCalled();
expect(funB).not.toHaveBeenCalled();
assert.strictEqual(val, '');

await sleep(50);

expect(funA).toHaveBeenCalled();
expect(funB).not.toHaveBeenCalled();
assert.strictEqual(val, 'A');

await sleep(50);

expect(funA).toHaveBeenCalledTimes(1);
expect(funB).toHaveBeenCalledTimes(1);
expect(val).toBe('AB');
assert.strictEqual(val, 'AB');
});

it('should verify task executed in time - - A:20, B:20, C:10 -> A, B, C', async () => {
const runner = new TaskExec();
const funA = jest.fn();
const funB = jest.fn();
const funC = jest.fn();
const funA = mock.fn();
const funB = mock.fn();
const funC = mock.fn();

runner.exec(funA, 50);
runner.exec(funB, 50);

await sleep(20);

expect(funA).not.toHaveBeenCalled();
expect(funB).not.toHaveBeenCalled();
assert.equal(funA.mock.callCount(), 0);
assert.equal(funB.mock.callCount(), 0);
runner.exec(funC, 10);

await sleep(50);

expect(funA).toHaveBeenCalledTimes(1);
expect(funB).toHaveBeenCalledTimes(1);
expect(funC).toHaveBeenCalledTimes(1);
assert.equal(funA.mock.callCount(), 1);
assert.equal(funB.mock.callCount(), 1);
assert.equal(funC.mock.callCount(), 1);
});
});
});
18 changes: 10 additions & 8 deletions src/common/utils/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { isPromise } from './utils';
import { describe, it } from 'node:test';
import assert from 'node:assert';

describe('utils', () => {
describe('isPromise', () => {
it('should return true if a Promise or an object with then attribute', () => {
expect(isPromise(Promise.resolve())).toBe(true);
expect(isPromise({ then: () => null })).toBe(true);
assert.equal(isPromise(Promise.resolve()), true);
assert.equal(isPromise({ then: () => null }), true);
});

it('should return false if not a Promise and not an object with then', () => {
expect(isPromise({})).toBe(false);
expect(isPromise(2)).toBe(false);
expect(isPromise(true)).toBe(false);
expect(isPromise(null)).toBe(false);
expect(isPromise(undefined)).toBe(false);
assert.equal(isPromise({}), false);
assert.equal(isPromise(2), false);
assert.equal(isPromise(true), false);
assert.equal(isPromise(null), false);
assert.equal(isPromise(undefined), false);
});
});
});
});
102 changes: 21 additions & 81 deletions src/debounce/debounce.spec.ts
Original file line number Diff line number Diff line change
@@ -1,108 +1,48 @@
import { debounce } from './debounce';
import { sleep } from '../common/test-utils';
import { describe, it, mock } from 'node:test';
import assert from 'node:assert';

describe('debounce', () => {
it('should make sure error thrown when decorator not set on method', () => {
try {
assert.throws(() => {
const nonValidDebounce: any = debounce(50);

class T {
@nonValidDebounce
boo: string;
@nonValidDebounce boo: string;
}
} catch (e) {
expect('@debounce is applicable only on a methods.').toBe(e.message);

return;
}

throw new Error('should not reach this line');
}, Error('@debounce is applicable only on a methods.'));
});

it('should verify method invocation is debounced', async () => {
const goo = mock.fn();

class T {
prop: number;

@debounce<T>(30)
foo(): void {
return this.goo();
}

goo(): void {
expect(this.prop).toBe(3);
@debounce<T>(50)
foo(x: number): void {
return goo(x);
}
}

const t = new T();
t.prop = 3;
const spy = jest.spyOn(T.prototype, 'goo');
t.foo(); // 15

expect(spy).not.toHaveBeenCalled();

await sleep(10);
expect(spy).toHaveBeenCalledTimes(0);
t.foo(); // 20
t.foo(1);
t.foo(2);

await sleep(20);
expect(spy).toHaveBeenCalledTimes(0);

await sleep(40);
expect(spy).toHaveBeenCalledTimes(1);
});

it('should verify method params are passed', (done) => {
class T {
@debounce<T>(5)
foo(x: number, y: number): void {
return this.goo(x, y);
}

goo(x: number, y: number): void {

}
}

const t = new T();
const spy = jest.spyOn(T.prototype, 'goo');
t.foo(1, 2);

setTimeout(() => {
expect(spy).toHaveBeenCalledWith(1, 2);
done();
}, 10);
});

it('should multi instances working', async () => {
class T {

@debounce<T>(30)
foo(): void {
return this.goo();
}

goo(): void {
}
}

const t1 = new T();
const t2 = new T();
const spy1 = jest.spyOn(t1, 'goo');
const spy2 = jest.spyOn(t1, 'goo');
t1.foo();
assert.equal(goo.mock.callCount(), 0);

expect(spy1).not.toHaveBeenCalled();
expect(spy2).not.toHaveBeenCalled();
await sleep(50);

await sleep(10);
expect(spy1).not.toHaveBeenCalled();
t2.foo(); // 20
t.foo(3);
assert.equal(goo.mock.callCount(), 1);
assert.equal(goo.mock.calls[0].arguments.length, 1);
assert.equal(goo.mock.calls[0].arguments[0], 2);

await sleep(30); // 40
expect(spy1).toHaveBeenCalledTimes(1);
await sleep(75);

await sleep(30); // 70
expect(spy1).toHaveBeenCalledTimes(1);
expect(spy2).toHaveBeenCalledTimes(1);
assert.equal(goo.mock.callCount(), 2);
});
});
});
2 changes: 1 addition & 1 deletion src/debounce/debounce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function debounce<T = any>(delayMs: number): Decorator<T> {
propertyName: keyof T,
descriptor: TypedPropertyDescriptor<Method<any>>,
): TypedPropertyDescriptor<Method<any>> => {
if (descriptor.value) {
if (descriptor && descriptor.value) {
const methodsMap = new WeakMap<any, Method<any>>();
const originalMethod = descriptor.value;

Expand Down
Loading

0 comments on commit 52f9f22

Please sign in to comment.