Remove any from codebase

This commit is contained in:
Pavel Mineev
2021-01-12 13:39:26 -06:00
committed by Umputun
parent 9518d1d83d
commit a144dd00e3
14 changed files with 55 additions and 40 deletions
+2
View File
@@ -21,12 +21,14 @@ module.exports = {
'no-undef': 'off',
'no-redeclare': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-explicit-any': 'error',
},
},
{
files: ['*.d.ts'],
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
},
{
+1 -1
View File
@@ -16,7 +16,7 @@ global.Headers = class HeadersMock extends Headers implements Headers {
delete(key: string) {
this.headers.delete(key);
}
forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) {
forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: unknown) {
this.headers.forEach((value, key) => {
callbackfn.call(thisArg || this, value, key, this);
});
+4 -4
View File
@@ -28,9 +28,9 @@ describe('fetcher', () => {
});
it('should throw special error object on 401 status', async () => {
const response = '<html>unauthorized nginx response</html>';
(window.fetch as any) = jest.fn().mockImplementation(async () => ({
window.fetch = jest.fn().mockImplementation(async () => ({
status: 401,
headers: new (window as any).Headers(),
headers: new Headers(),
json: async () => {
throw new Error('json parse error');
},
@@ -48,9 +48,9 @@ describe('fetcher', () => {
});
});
it('should throw "Something went wrong." object on unknown status', async () => {
(jest.spyOn(window, 'fetch') as any).mockImplementation(async () => ({
window.fetch = jest.fn().mockImplementation(async () => ({
status: 400,
headers: new (window as any).Headers(),
headers: new Headers(),
async json() {
throw new Error('json parse error');
},
+2 -2
View File
@@ -12,7 +12,7 @@ describe('getJsonItem', () => {
});
it('should update json in localStoeage', () => {
setJsonItem<any[]>(LS_KEY, []);
setJsonItem(LS_KEY, []);
expect(localStorage.getItem(LS_KEY)).toBe('[]');
});
});
@@ -88,7 +88,7 @@ describe('updateJsonItem', () => {
it('should update data in localStorage with merge', () => {
localStorage.setItem(LS_KEY, JSON.stringify([3, 4, 5]));
updateJsonItem<any[]>(LS_KEY, data => [1, 2, ...data]);
updateJsonItem(LS_KEY, (data: unknown[]) => [1, 2, ...data]);
expect(localStorage.getItem(LS_KEY)).toBe(JSON.stringify([1, 2, 3, 4, 5]));
});
+6 -5
View File
@@ -21,7 +21,7 @@ export const removeItem = IS_STORAGE_AVAILABLE
console.error(failMessage); // eslint-disable-line no-console
};
export function getJsonItem<T = any>(key: string): T | null {
export function getJsonItem<T = unknown>(key: string): T | null {
try {
const json = getItem(key);
@@ -38,7 +38,7 @@ export function getJsonItem<T = any>(key: string): T | null {
}
}
export function setJsonItem<T = any>(key: string, data: T) {
export function setJsonItem<T = unknown>(key: string, data: T) {
try {
setItem(key, JSON.stringify(data));
} catch (e) {
@@ -48,10 +48,11 @@ export function setJsonItem<T = any>(key: string, data: T) {
export function updateJsonItem<T extends {}>(key: string, value: (data: T) => T): void;
export function updateJsonItem<T extends {}>(key: string, value: T): void;
export function updateJsonItem<T = Record<string, unknown>>(key: string, value: T) {
const savedData = getJsonItem<any>(key);
export function updateJsonItem<T extends unknown[]>(key: string, value: T): void;
export function updateJsonItem<T>(key: string, value: T) {
const savedData = getJsonItem<T>(key);
if (Array.isArray(value)) {
if (Array.isArray(value) && Array.isArray(savedData)) {
setJsonItem(key, [...savedData, ...value]);
return;
}
@@ -5,6 +5,7 @@ import { Middleware } from 'redux';
import { Provider } from 'react-redux';
import { IntlProvider } from 'react-intl';
import type { User } from 'common/types';
import enMessages from 'locales/en.json';
import AuthPanel, { Props } from './auth-panel';
@@ -61,7 +62,7 @@ describe('<AuthPanel />', () => {
...DefaultProps,
user: null,
postInfo: { ...DefaultProps.postInfo, read_only: true },
hiddenUsers: { hidden_joe: {} as any },
hiddenUsers: { hidden_joe: {} as User },
} as Props);
const adminAction = element.find('.auth-panel__admin-action');
@@ -76,7 +77,7 @@ describe('<AuthPanel />', () => {
...DefaultProps,
user: null,
postInfo: { ...DefaultProps.postInfo, read_only: true },
hiddenUsers: { hidden_joe: {} as any },
hiddenUsers: { hidden_joe: {} as User },
} as Props);
const firstCol = element.find('.auth-panel__column').first();
@@ -20,22 +20,26 @@ jest.mock('utils/jwt', () => ({
jest.mock('common/api');
const sendEmailVerificationRequestMock = sendEmailVerificationRequest as jest.Mock<
ReturnType<typeof sendEmailVerificationRequest>
>;
function simulateInput(input: ReactWrapper, value: string) {
input.getDOMNode<HTMLTextAreaElement>().value = value;
input.simulate('input');
}
describe('EmailLoginForm', () => {
const testUser = ({} as any) as User;
const testUser = {} as User;
const onSuccess = jest.fn(async () => undefined);
const onSignIn = jest.fn(async () => testUser);
beforeEach(() => {
(sendEmailVerificationRequest as any).mockReset();
sendEmailVerificationRequestMock.mockReset();
});
it('works', async () => {
(sendEmailVerificationRequest as any).mockResolvedValueOnce({});
sendEmailVerificationRequestMock.mockResolvedValueOnce();
const el = mount<Props, State>(
<IntlProvider locale="en" messages={enMessages}>
<EmailLoginForm onSignIn={onSignIn} onSuccess={onSuccess} theme="light" />
@@ -45,7 +49,7 @@ describe('EmailLoginForm', () => {
simulateInput(el.find(`input[name="username"]`), 'someone');
el.find('form').simulate('submit');
await sleep(100);
expect(sendEmailVerificationRequest).toBeCalledWith('someone', 'someone@example.com');
expect(sendEmailVerificationRequestMock).toBeCalledWith('someone', 'someone@example.com');
el.update();
simulateInput(el.find(`textarea[name="token"]`), 'abcd');
@@ -58,7 +62,7 @@ describe('EmailLoginForm', () => {
});
it('should send form by pasting token', async () => {
(sendEmailVerificationRequest as any).mockResolvedValueOnce({});
sendEmailVerificationRequestMock.mockResolvedValueOnce();
const onSignIn = jest.fn(async () => testUser);
const wrapper = mount<Props, State>(
@@ -78,7 +82,7 @@ describe('EmailLoginForm', () => {
});
it('should show error "Token is expired" on paste', async () => {
(sendEmailVerificationRequest as any).mockResolvedValueOnce({});
sendEmailVerificationRequestMock.mockResolvedValueOnce();
const onSignIn = jest.fn(async () => testUser);
const wrapper = mount<Props, State>(
@@ -15,7 +15,6 @@ import { sleep } from 'utils/sleep';
import { Input } from 'components/input';
import { Button } from 'components/button';
import { Dropdown } from 'components/dropdown';
import TextareaAutosize from 'components/comment-form/textarea-autosize';
import enMessages from 'locales/en.json';
import { LS_EMAIL_KEY } from 'common/constants';
@@ -161,10 +160,10 @@ describe('<SubscribeByEmailForm/>', () => {
await sleep(0);
wrapper.update();
const textarea = wrapper.find(TextareaAutosize);
const onInputToken = textarea.prop('onInput') as (e: any) => void;
const textarea = wrapper.find('textarea');
act(() => onInputToken(makeInputEvent(validToken)));
textarea.getDOMNode<HTMLTextAreaElement>().value = validToken;
textarea.simulate('input');
await sleep(0);
wrapper.update();
@@ -9,8 +9,9 @@ import * as localStorageModule from 'common/local-storage';
import { CommentForm, CommentFormProps, messages } from './comment-form';
import { SubscribeByEmail } from './__subscribe-by-email';
import TextareaAutosize from './textarea-autosize';
import { IntlShape } from 'react-intl';
function createEvent<E extends Event, T = any>(type: string, value: T): E {
function createEvent<E extends Event, T = unknown>(type: string, value: T): E {
const event = new Event(type);
Object.defineProperty(event, 'target', { value });
@@ -31,7 +32,7 @@ const intl = {
formatMessage(message: { defaultMessage: string }) {
return message.defaultMessage || '';
},
} as any;
} as IntlShape;
describe('<CommentForm />', () => {
it('should shallow without control panel, preview button, and rss links in "simple view" mode', () => {
@@ -1,6 +1,6 @@
import { h } from 'preact';
import { mount as enzymeMount } from 'enzyme';
import { IntlProvider } from 'react-intl';
import { IntlProvider, IntlShape } from 'react-intl';
import enMessages from 'locales/en.json';
import type { User, Comment as CommentType, PostInfo } from 'common/types';
@@ -9,7 +9,7 @@ import { sleep } from 'utils/sleep';
import Comment, { CommentProps } from './comment';
const mount = (component: any) =>
const mount = <T extends JSX.Element>(component: T) =>
enzymeMount(
<IntlProvider locale="en" messages={enMessages}>
{component}
@@ -20,7 +20,7 @@ const intl = {
formatMessage(message: { defaultMessage: string }) {
return message.defaultMessage || '';
},
} as any;
} as IntlShape;
const DefaultProps: Partial<CommentProps> = {
CommentForm: null,
+1
View File
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useCallback, useMemo } from 'preact/compat';
import { useDispatch } from 'react-redux';
import { BoundActionCreator, BoundActionCreators } from 'utils/actionBinder';
+4 -3
View File
@@ -1,4 +1,5 @@
import { Comment } from 'common/types';
import { StoreState } from 'store';
import { setCollapse } from './actions';
import { THREAD_SET_COLLAPSE } from './types';
@@ -6,11 +7,11 @@ import { THREAD_SET_COLLAPSE } from './types';
describe('collapsedThreads', () => {
it('should set collapsed to true', () => {
const comment = { id: 'some-id' } as Comment;
const node = { comment, replies: [] };
const state = { collapsedThreads: {}, comments: [node] };
const state = { collapsedThreads: {} } as StoreState;
const dispatch = jest.fn();
const getState = jest.fn(() => state) as any;
const getState = jest.fn(() => state);
setCollapse(comment.id, true)(dispatch, getState, undefined);
expect(dispatch).toBeCalledWith({
type: THREAD_SET_COLLAPSE,
+12 -7
View File
@@ -1,12 +1,16 @@
import * as api from 'common/api';
import { getUser, logIn as logInApi, logOut } from 'common/api';
import { User } from 'common/types';
import { fetchUser, logIn, logout } from './actions';
import { user } from './reducers';
import { USER_SET } from './types';
import { USER_ACTIONS, USER_SET } from './types';
jest.mock('common/api');
const getUserMock = (getUser as unknown) as jest.Mock<ReturnType<typeof getUser>>;
const logInMock = (logInApi as unknown) as jest.Mock<ReturnType<typeof logInApi>>;
const logOutMock = (logOut as unknown) as jest.Mock<ReturnType<typeof logOut>>;
afterEach(() => {
jest.resetModules();
});
@@ -14,12 +18,13 @@ afterEach(() => {
describe('user', () => {
it('should return null by default', () => {
const action = { type: 'OTHER' };
const newState = user(null, action as any);
const newState = user(null, action as USER_ACTIONS);
expect(newState).toEqual(null);
});
it('should set state of user on fetchUser', async () => {
(api.getUser as any).mockImplementation(
getUserMock.mockImplementation(
async (): Promise<User> =>
({
id: 'john',
@@ -41,7 +46,7 @@ describe('user', () => {
});
it('should set state of user on logIn', async () => {
(api.logIn as any).mockImplementation(
logInMock.mockImplementation(
async (): Promise<User> =>
({
id: 'john',
@@ -63,7 +68,7 @@ describe('user', () => {
});
it('should NOT set state of user on failed logIn', async () => {
(api.logIn as any).mockImplementation(
logInMock.mockImplementation(
async (): Promise<User> => {
throw new Error('Unauthorized');
}
@@ -75,7 +80,7 @@ describe('user', () => {
});
it('should unset user on logOut', async () => {
(api.logOut as any).mockImplementation(async (): Promise<void> => undefined);
logOutMock.mockImplementation(async (): Promise<void> => undefined);
const dispatch = jest.fn();
const getState = jest.fn();
await logout()(dispatch, getState, undefined);
+1 -1
View File
@@ -6,7 +6,7 @@ export default function debounce<T extends unknown[]>(
): (...args: Parameters<FnType<T>>) => void {
let timeout: number | undefined;
return function (this: any, ...args): void {
return function (this: unknown, ...args): void {
const laterCall = (): unknown => fn.apply(this, args);
window.clearTimeout(timeout);
timeout = window.setTimeout(laterCall, wait);