Merge pull request #899 from cleverjam/useCopyToClipboard-tests

refactor: use copy to clipboard
This commit is contained in:
Vadim Dalecky 2020-01-17 00:31:04 -08:00 committed by GitHub
commit 5d4785750d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 133 additions and 15 deletions

View File

@ -18,31 +18,46 @@ const useCopyToClipboard = (): [CopyToClipboardState, (value: string) => void] =
});
const copyToClipboard = useCallback(value => {
if (!isMounted()) {
return;
}
let noUserInteraction;
let normalizedValue;
try {
if (process.env.NODE_ENV === 'development') {
if (typeof value !== 'string') {
console.error(`Cannot copy typeof ${typeof value} to clipboard, must be a string`);
}
}
const noUserInteraction = writeText(value);
if (!isMounted()) {
// only strings and numbers casted to strings can be copied to clipboard
if (typeof value !== 'string' && typeof value !== 'number') {
const error = new Error(`Cannot copy typeof ${typeof value} to clipboard, must be a string`);
if (process.env.NODE_ENV === 'development') console.error(error);
setState({
value,
error,
noUserInteraction: true,
});
return;
}
// empty strings are also considered invalid
else if (value === '') {
const error = new Error(`Cannot copy empty string to clipboard.`);
if (process.env.NODE_ENV === 'development') console.error(error);
setState({
value,
error,
noUserInteraction: true,
});
return;
}
normalizedValue = value.toString();
noUserInteraction = writeText(normalizedValue);
setState({
value,
value: normalizedValue,
error: undefined,
noUserInteraction,
});
} catch (error) {
if (!isMounted()) {
return;
}
setState({
value: undefined,
value: normalizedValue,
error,
noUserInteraction: true,
noUserInteraction,
});
}
}, []);

View File

@ -0,0 +1,103 @@
import writeText from 'copy-to-clipboard';
import { renderHook, act } from '@testing-library/react-hooks';
import { useCopyToClipboard } from '../src';
const valueToRaiseMockException = 'fake input causing exception in copy to clipboard';
jest.mock('copy-to-clipboard', () =>
jest.fn().mockImplementation(input => {
if (input === valueToRaiseMockException) {
throw new Error(input);
}
return true;
})
);
jest.spyOn(global.console, 'error').mockImplementation(() => {});
describe('useCopyToClipboard', () => {
let hook;
beforeEach(() => {
hook = renderHook(() => useCopyToClipboard());
});
afterAll(() => {
jest.restoreAllMocks();
});
it('should be defined ', () => {
expect(useCopyToClipboard).toBeDefined();
});
it('should pass a given value to copy to clipboard and set state', () => {
const testValue = 'test';
let [state, copyToClipboard] = hook.result.current;
act(() => copyToClipboard(testValue));
[state, copyToClipboard] = hook.result.current;
expect(writeText).toBeCalled();
expect(state.value).toBe(testValue);
expect(state.noUserInteraction).toBe(true);
expect(state.error).not.toBeDefined();
});
it('should not call writeText if passed an invalid input and set state', () => {
let testValue = {}; // invalid value
let [state, copyToClipboard] = hook.result.current;
act(() => copyToClipboard(testValue));
[state, copyToClipboard] = hook.result.current;
expect(writeText).not.toBeCalled();
expect(state.value).toBe(testValue);
expect(state.noUserInteraction).toBe(true);
expect(state.error).toBeDefined();
testValue = ''; // emtpy string is also invalid
act(() => copyToClipboard(testValue));
[state, copyToClipboard] = hook.result.current;
expect(writeText).not.toBeCalled();
expect(state.value).toBe(testValue);
expect(state.noUserInteraction).toBe(true);
expect(state.error).toBeDefined();
});
it('should catch exception thrown by copy-to-clipboard and set state', () => {
let [state, copyToClipboard] = hook.result.current;
act(() => copyToClipboard(valueToRaiseMockException));
[state, copyToClipboard] = hook.result.current;
expect(writeText).toBeCalledWith(valueToRaiseMockException);
expect(state.value).toBe(valueToRaiseMockException);
expect(state.noUserInteraction).not.toBeDefined();
expect(state.error).toStrictEqual(new Error(valueToRaiseMockException));
});
it('should return initial state while unmounted', () => {
hook.unmount();
const [state, copyToClipboard] = hook.result.current;
act(() => copyToClipboard('value'));
expect(state.value).not.toBeDefined();
expect(state.error).not.toBeDefined();
expect(state.noUserInteraction).toBe(true);
});
it('should console error if in dev environment', () => {
const ORIGINAL_NODE_ENV = process.env.NODE_ENV;
const testValue = {}; // invalid value
process.env.NODE_ENV = 'development';
let [state, copyToClipboard] = hook.result.current;
act(() => copyToClipboard(testValue));
process.env.NODE_ENV = ORIGINAL_NODE_ENV;
[state, copyToClipboard] = hook.result.current;
expect(writeText).not.toBeCalled();
expect(console.error).toBeCalled();
expect(state.value).toBe(testValue);
expect(state.noUserInteraction).toBe(true);
expect(state.error).toBeDefined();
});
});