Refactor code to comply with ESLint rules
Major refactoring using ESLint with rules from AirBnb and Vue. Enable most of the ESLint rules and do necessary linting in the code. Also add more information for rules that are disabled to describe what they are and why they are disabled. Allow logging (`console.log`) in test files, and in development mode (e.g. when working with `npm run serve`), but disable it when environment is production (as pre-configured by Vue). Also add flag (`--mode production`) in `lint:eslint` command so production linting is executed earlier in lifecycle. Disable rules that requires a separate work. Such as ESLint rules that are broken in TypeScript: no-useless-constructor (eslint/eslint#14118) and no-shadow (eslint/eslint#13014).
This commit is contained in:
@@ -1,138 +1,158 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { throttle, ITimer } from '@/presentation/components/Shared/Throttle';
|
||||
import { throttle, ITimer, TimeoutType } from '@/presentation/components/Shared/Throttle';
|
||||
import { EventSource } from '@/infrastructure/Events/EventSource';
|
||||
import { IEventSubscription } from '@/infrastructure/Events/IEventSource';
|
||||
|
||||
describe('throttle', () => {
|
||||
it('throws if callback is undefined', () => {
|
||||
// arrange
|
||||
const expectedError = 'undefined callback';
|
||||
const callback = undefined;
|
||||
it('throws if callback is undefined', () => {
|
||||
// arrange
|
||||
const expectedError = 'undefined callback';
|
||||
const callback = undefined;
|
||||
// act
|
||||
const act = () => throttle(callback, 500);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
describe('throws if waitInMs is negative or zero', () => {
|
||||
// arrange
|
||||
const testCases = [
|
||||
{ value: 0, expectedError: 'no delay to throttle' },
|
||||
{ value: -2, expectedError: 'negative delay' },
|
||||
];
|
||||
const noopCallback = () => { /* do nothing */ };
|
||||
for (const testCase of testCases) {
|
||||
it(`"${testCase.value}" throws "${testCase.expectedError}"`, () => {
|
||||
// act
|
||||
const act = () => throttle(callback, 500);
|
||||
const waitInMs = testCase.value;
|
||||
const act = () => throttle(noopCallback, waitInMs);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
describe('throws if waitInMs is negative or zero', () => {
|
||||
// arrange
|
||||
const testCases = [
|
||||
{ value: 0, expectedError: 'no delay to throttle' },
|
||||
{ value: -2, expectedError: 'negative delay' },
|
||||
];
|
||||
const callback = () => { return; };
|
||||
for (const testCase of testCases) {
|
||||
it(`"${testCase.value}" throws "${testCase.expectedError}"`, () => {
|
||||
// act
|
||||
const waitInMs = testCase.value;
|
||||
const act = () => throttle(callback, waitInMs);
|
||||
// assert
|
||||
expect(act).to.throw(testCase.expectedError);
|
||||
});
|
||||
}
|
||||
});
|
||||
it('should call the callback immediately', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const throttleFunc = throttle(callback, 500, timer);
|
||||
// act
|
||||
throttleFunc();
|
||||
// assert
|
||||
expect(totalRuns).to.equal(1);
|
||||
});
|
||||
it('should call the callback again after the timeout', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const waitInMs = 500;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
throttleFunc();
|
||||
totalRuns--; // So we don't count the initial run
|
||||
throttleFunc();
|
||||
timer.tickNext(waitInMs);
|
||||
// assert
|
||||
expect(totalRuns).to.equal(1);
|
||||
});
|
||||
it('should call the callback at most once at given time', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const waitInMs = 500;
|
||||
const totalCalls = 10;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
for (let i = 0; i < totalCalls; i++) {
|
||||
timer.setCurrentTime(waitInMs / totalCalls * i);
|
||||
throttleFunc();
|
||||
}
|
||||
// assert
|
||||
expect(totalRuns).to.equal(2); // one initial and one at the end
|
||||
});
|
||||
it('should call the callback as long as delay is waited', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const waitInMs = 500;
|
||||
const expectedTotalRuns = 10;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
for (let i = 0; i < expectedTotalRuns; i++) {
|
||||
throttleFunc();
|
||||
timer.tickNext(waitInMs);
|
||||
}
|
||||
// assert
|
||||
expect(totalRuns).to.equal(expectedTotalRuns);
|
||||
});
|
||||
it('should call arguments as expected', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
const expected = [ 1, 2, 3 ];
|
||||
const actual = new Array<number>();
|
||||
const callback = (arg: number) => { actual.push(arg); };
|
||||
const waitInMs = 500;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
for (const arg of expected) {
|
||||
throttleFunc(arg);
|
||||
timer.tickNext(waitInMs);
|
||||
}
|
||||
// assert
|
||||
expect(expected).to.deep.equal(actual);
|
||||
});
|
||||
expect(act).to.throw(testCase.expectedError);
|
||||
});
|
||||
}
|
||||
});
|
||||
it('should call the callback immediately', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const throttleFunc = throttle(callback, 500, timer);
|
||||
// act
|
||||
throttleFunc();
|
||||
// assert
|
||||
expect(totalRuns).to.equal(1);
|
||||
});
|
||||
it('should call the callback again after the timeout', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const waitInMs = 500;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
throttleFunc();
|
||||
totalRuns--; // So we don't count the initial run
|
||||
throttleFunc();
|
||||
timer.tickNext(waitInMs);
|
||||
// assert
|
||||
expect(totalRuns).to.equal(1);
|
||||
});
|
||||
it('should call the callback at most once at given time', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const waitInMs = 500;
|
||||
const totalCalls = 10;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
for (let currentCall = 0; currentCall < totalCalls; currentCall++) {
|
||||
const currentTime = (waitInMs / totalCalls) * currentCall;
|
||||
timer.setCurrentTime(currentTime);
|
||||
throttleFunc();
|
||||
}
|
||||
// assert
|
||||
expect(totalRuns).to.equal(2); // one initial and one at the end
|
||||
});
|
||||
it('should call the callback as long as delay is waited', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
let totalRuns = 0;
|
||||
const callback = () => totalRuns++;
|
||||
const waitInMs = 500;
|
||||
const expectedTotalRuns = 10;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
for (let i = 0; i < expectedTotalRuns; i++) {
|
||||
throttleFunc();
|
||||
timer.tickNext(waitInMs);
|
||||
}
|
||||
// assert
|
||||
expect(totalRuns).to.equal(expectedTotalRuns);
|
||||
});
|
||||
it('should call arguments as expected', () => {
|
||||
// arrange
|
||||
const timer = new TimerMock();
|
||||
const expected = [1, 2, 3];
|
||||
const actual = new Array<number>();
|
||||
const callback = (arg: number) => { actual.push(arg); };
|
||||
const waitInMs = 500;
|
||||
const throttleFunc = throttle(callback, waitInMs, timer);
|
||||
// act
|
||||
for (const arg of expected) {
|
||||
throttleFunc(arg);
|
||||
timer.tickNext(waitInMs);
|
||||
}
|
||||
// assert
|
||||
expect(expected).to.deep.equal(actual);
|
||||
});
|
||||
});
|
||||
|
||||
class TimerMock implements ITimer {
|
||||
private timeChanged = new EventSource<number>();
|
||||
private subscriptions = new Array<IEventSubscription>();
|
||||
private currentTime = 0;
|
||||
public setTimeout(callback: () => void, ms: number): NodeJS.Timeout {
|
||||
const runTime = this.currentTime + ms;
|
||||
const subscription = this.timeChanged.on((time) => {
|
||||
if (time >= runTime) {
|
||||
callback();
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
});
|
||||
this.subscriptions.push(subscription);
|
||||
return (this.subscriptions.length - 1) as any;
|
||||
}
|
||||
public clearTimeout(timeoutId: NodeJS.Timeout): void {
|
||||
this.subscriptions[timeoutId as any].unsubscribe();
|
||||
}
|
||||
public dateNow(): number {
|
||||
return this.currentTime;
|
||||
}
|
||||
public tickNext(ms: number): void {
|
||||
this.setCurrentTime(this.currentTime + ms);
|
||||
}
|
||||
public setCurrentTime(ms: number): void {
|
||||
this.currentTime = ms;
|
||||
this.timeChanged.notify(this.currentTime);
|
||||
}
|
||||
private timeChanged = new EventSource<number>();
|
||||
|
||||
private subscriptions = new Array<IEventSubscription>();
|
||||
|
||||
private currentTime = 0;
|
||||
|
||||
public setTimeout(callback: () => void, ms: number): TimeoutType {
|
||||
const runTime = this.currentTime + ms;
|
||||
const subscription = this.timeChanged.on((time) => {
|
||||
if (time >= runTime) {
|
||||
callback();
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
});
|
||||
this.subscriptions.push(subscription);
|
||||
const id = this.subscriptions.length - 1;
|
||||
return TimerMock.mockTimeout(id);
|
||||
}
|
||||
|
||||
public clearTimeout(timeoutId: TimeoutType): void {
|
||||
this.subscriptions[+timeoutId].unsubscribe();
|
||||
}
|
||||
|
||||
public dateNow(): number {
|
||||
return this.currentTime;
|
||||
}
|
||||
|
||||
public tickNext(ms: number): void {
|
||||
this.setCurrentTime(this.currentTime + ms);
|
||||
}
|
||||
|
||||
public setCurrentTime(ms: number): void {
|
||||
this.currentTime = ms;
|
||||
this.timeChanged.notify(this.currentTime);
|
||||
}
|
||||
|
||||
private static mockTimeout(subscriptionId: number): TimeoutType {
|
||||
const throwNodeSpecificCode = () => { throw new Error('node specific code'); };
|
||||
return {
|
||||
[Symbol.toPrimitive]: () => subscriptionId,
|
||||
hasRef: throwNodeSpecificCode,
|
||||
refresh: throwNodeSpecificCode,
|
||||
ref: throwNodeSpecificCode,
|
||||
unref: throwNodeSpecificCode,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user