import { copyToClipboard, escapeHtml, getRandomHTMLId, isElementInContainer, isTargetInElement, setInternalsValidityFromHtmlElement, setInternalsValidityFromOdsComponent, submitFormOnClick, submitFormOnEnter } from '../../src/utils/dom';
describe('utils dom', () => {
beforeEach(jest.clearAllMocks);
describe('copyToClipboard', () => {
Object.assign(navigator, {
clipboard: {
writeText: jest.fn(),
},
});
it('should call the navigator writeText method with empty value if not set', async() => {
await copyToClipboard();
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('');
});
it('should call the navigator writeText method with given value', async() => {
const dummyValue = 'dummy value';
await copyToClipboard(dummyValue);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(dummyValue);
});
});
describe('escapeHtml', () => {
it('should return an empty string if no value passed', () => {
// @ts-ignore for test purpose
expect(escapeHtml()).toBe('');
// @ts-ignore for test purpose
expect(escapeHtml(undefined)).toBe('');
// @ts-ignore for test purpose
expect(escapeHtml(null)).toBe('');
});
it('should return same string if nothing to escape', () => {
expect(escapeHtml('')).toBe('');
expect(escapeHtml('Hello')).toBe('Hello');
});
it('should return an escaped value', () => {
expect(escapeHtml('
Hello World
')).toBe('<h1>Hello World</h1>');
});
});
describe('getRandomHTMLId', () => {
it('should return unique HTML valid ids', async() => {
const htmlId1 = getRandomHTMLId();
const htmlId2 = getRandomHTMLId();
expect(htmlId1).not.toBe(htmlId2);
expect(/^[0-9]/.test(htmlId1)).toBe(false);
expect(/^[0-9]/.test(htmlId2)).toBe(false);
});
});
describe('isElementInContainer', () => {
const dummyContainer = {
getBoundingClientRect: () => ({
bottom: 200,
left: 100,
right: 200,
top: 100,
}),
} as unknown as HTMLElement;
const dummyElement = {
getBoundingClientRect: jest.fn(),
} as unknown as HTMLElement;
it('should return false if element is partially higher than its container', () => {
(dummyElement.getBoundingClientRect as jest.Mock).mockReturnValueOnce({
bottom: 200,
left: 200,
right: 100,
top: 50,
});
expect(isElementInContainer(dummyElement, dummyContainer)).toBe(false);
});
it('should return false if element is partially under than its container', () => {
(dummyElement.getBoundingClientRect as jest.Mock).mockReturnValueOnce({
bottom: 250,
left: 200,
right: 100,
top: 100,
});
expect(isElementInContainer(dummyElement, dummyContainer)).toBe(false);
});
it('should return false if element is partially on the left of its container', () => {
(dummyElement.getBoundingClientRect as jest.Mock).mockReturnValueOnce({
bottom: 200,
left: 50,
right: 200,
top: 100,
});
expect(isElementInContainer(dummyElement, dummyContainer)).toBe(false);
});
it('should return false if element is partially on the right of its container', () => {
(dummyElement.getBoundingClientRect as jest.Mock).mockReturnValueOnce({
bottom: 200,
left: 100,
right: 250,
top: 100,
});
expect(isElementInContainer(dummyElement, dummyContainer)).toBe(false);
});
it('should return true if element is in its container', () => {
(dummyElement.getBoundingClientRect as jest.Mock).mockReturnValueOnce({
bottom: 175,
left: 125,
right: 175,
top: 125,
});
expect(isElementInContainer(dummyElement, dummyContainer)).toBe(true);
});
});
describe('isTargetInElement', () => {
const containSpy = jest.fn();
const includeSpy = jest.fn();
const mockElement = {
contains: containSpy,
} as unknown as HTMLElement;
const mockEvent = {
composedPath: jest.fn().mockReturnValue({
includes: includeSpy,
}),
target: 'dummy target',
} as unknown as Event;
it('should return false if element is empty', () => {
expect(isTargetInElement(mockEvent)).toBe(false);
});
it('should return false if target is not contained by the element or the path', () => {
containSpy.mockReturnValueOnce(false);
includeSpy.mockReturnValueOnce(false);
const mockEvent = {
composedPath: jest.fn().mockReturnValue({
includes: includeSpy,
}),
target: 'dummy target',
} as unknown as Event;
expect(isTargetInElement(mockEvent, mockElement)).toBe(false);
expect(mockElement.contains).toHaveBeenCalledWith(mockEvent.target);
expect(includeSpy).toHaveBeenCalledWith(mockElement);
});
it('should return true if target is contained by the element', () => {
containSpy.mockReturnValueOnce(true);
expect(isTargetInElement(mockEvent, mockElement)).toBe(true);
expect(mockElement.contains).toHaveBeenCalledWith(mockEvent.target);
expect(includeSpy).not.toHaveBeenCalled();
});
it('should return true if target is included in the event path', () => {
containSpy.mockReturnValueOnce(false);
includeSpy.mockReturnValueOnce(true);
expect(isTargetInElement(mockEvent, mockElement)).toBe(true);
expect(mockElement.contains).toHaveBeenCalledWith(mockEvent.target);
expect(includeSpy).toHaveBeenCalledWith(mockElement);
});
});
describe('setInternalsValidityFromHtmlElement', () => {
const mockInternals = {
setValidity: jest.fn(),
} as unknown as ElementInternals;
it('should set the validity to empty if valid', () => {
const mockFormElement = {
validity: {
valid: true,
},
} as unknown as HTMLInputElement;
setInternalsValidityFromHtmlElement(mockFormElement, mockInternals);
expect(mockInternals.setValidity).toHaveBeenCalledTimes(1);
expect(mockInternals.setValidity).toHaveBeenCalledWith({});
});
it('should set the same validity flags as the form element if invalid', () => {
const mockValidityState = {
badInput: true,
customError: true,
patternMismatch: true,
rangeOverflow: true,
rangeUnderflow: true,
stepMismatch: true,
tooLong: true,
tooShort: true,
typeMismatch: true,
valueMissing: true,
};
const mockFormElement = {
validationMessage: 'dummy validation message',
validity: {
...mockValidityState,
valid: false,
},
} as unknown as HTMLInputElement;
setInternalsValidityFromHtmlElement(mockFormElement, mockInternals);
expect(mockInternals.setValidity).toHaveBeenCalledTimes(Object.keys(mockValidityState).length);
Object.entries(mockValidityState).forEach(([key, value]) => {
expect(mockInternals.setValidity).toHaveBeenCalledWith({ [key]: value }, mockFormElement.validationMessage, mockFormElement);
});
});
});
describe('setInternalsValidityFromOdsComponent', () => {
const mockInternals = {
setValidity: jest.fn(),
} as unknown as ElementInternals;
it('should set the validity to empty if valid', async() => {
const mockOdsFormElement = {
getValidationMessage: jest.fn().mockImplementation(() => Promise.resolve('')),
getValidity: jest.fn().mockImplementation(() => Promise.resolve({ valid: true })),
} as unknown as HTMLElement & {
getValidationMessage: () => Promise,
getValidity: () => Promise,
};
await setInternalsValidityFromOdsComponent(mockOdsFormElement, mockInternals);
expect(mockInternals.setValidity).toHaveBeenCalledTimes(1);
expect(mockInternals.setValidity).toHaveBeenCalledWith({});
});
it('should set the same validity flags as the form element if invalid', async() => {
const dummyValidationMessage = 'dummy validation message';
const mockValidityState = {
badInput: true,
customError: true,
patternMismatch: true,
rangeOverflow: true,
rangeUnderflow: true,
stepMismatch: true,
tooLong: true,
tooShort: true,
typeMismatch: true,
valueMissing: true,
};
const mockOdsFormElement = {
getValidationMessage: jest.fn().mockImplementation(() => Promise.resolve(dummyValidationMessage)),
getValidity: jest.fn().mockImplementation(() => Promise.resolve({
...mockValidityState,
valid: false,
})),
} as unknown as HTMLElement & {
getValidationMessage: () => Promise,
getValidity: () => Promise,
};
await setInternalsValidityFromOdsComponent(mockOdsFormElement, mockInternals);
expect(mockInternals.setValidity).toHaveBeenCalledTimes(Object.keys(mockValidityState).length);
Object.entries(mockValidityState).forEach(([key, value]) => {
expect(mockInternals.setValidity).toHaveBeenCalledWith({ [key]: value }, dummyValidationMessage, mockOdsFormElement);
});
});
});
describe('submitFormOnEnter', () => {
const mockForm = {
requestSubmit: jest.fn(),
} as unknown as HTMLFormElement;
it('should do nothing if event key is not Enter', () => {
submitFormOnEnter({ key: 'Space' } as unknown as KeyboardEvent, mockForm);
expect(mockForm.requestSubmit).not.toHaveBeenCalled();
});
it('should do nothing if no form is passed', () => {
submitFormOnEnter({ key: 'Enter' } as unknown as KeyboardEvent, null);
expect(mockForm.requestSubmit).not.toHaveBeenCalled();
});
it('should request submit on Enter press', () => {
submitFormOnEnter({ key: 'Enter' } as unknown as KeyboardEvent, mockForm);
expect(mockForm.requestSubmit).toHaveBeenCalled();
});
});
describe('submitFormOnClick', () => {
const mockForm = {
requestSubmit: jest.fn(),
} as unknown as HTMLFormElement;
it('should do nothing if event button is not 0', () => {
submitFormOnClick({ button: 1 } as unknown as MouseEvent, mockForm);
expect(mockForm.requestSubmit).not.toHaveBeenCalled();
});
it('should do nothing if no form is passed', () => {
submitFormOnClick({ button: 0 } as unknown as MouseEvent, null);
expect(mockForm.requestSubmit).not.toHaveBeenCalled();
});
it('should request submit on click', () => {
submitFormOnClick({ button: 0 } as unknown as MouseEvent, mockForm);
expect(mockForm.requestSubmit).toHaveBeenCalled();
});
});
});