• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2023 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {
16  bindEventListener,
17  elementIsEditable,
18  findRef,
19  isOrContains,
20  toHTMLElement,
21} from './dom_utils';
22
23describe('isOrContains', () => {
24  const parent = document.createElement('div');
25  const child = document.createElement('div');
26  parent.appendChild(child);
27
28  it('finds child in parent', () => {
29    expect(isOrContains(parent, child)).toBeTruthy();
30  });
31
32  it('finds child in child', () => {
33    expect(isOrContains(child, child)).toBeTruthy();
34  });
35
36  it('does not find parent in child', () => {
37    expect(isOrContains(child, parent)).toBeFalsy();
38  });
39});
40
41describe('findRef', () => {
42  const parent = document.createElement('div');
43  const fooChild = document.createElement('div');
44  fooChild.setAttribute('ref', 'foo');
45  parent.appendChild(fooChild);
46  const barChild = document.createElement('div');
47  barChild.setAttribute('ref', 'bar');
48  parent.appendChild(barChild);
49
50  it('should find refs in parent divs', () => {
51    expect(findRef(parent, 'foo')).toEqual(fooChild);
52    expect(findRef(parent, 'bar')).toEqual(barChild);
53  });
54
55  it('should find refs in self divs', () => {
56    expect(findRef(fooChild, 'foo')).toEqual(fooChild);
57    expect(findRef(barChild, 'bar')).toEqual(barChild);
58  });
59
60  it('should fail to find ref in unrelated divs', () => {
61    const unrelated = document.createElement('div');
62    expect(findRef(unrelated, 'foo')).toBeNull();
63    expect(findRef(fooChild, 'bar')).toBeNull();
64    expect(findRef(barChild, 'foo')).toBeNull();
65  });
66});
67
68describe('toHTMLElement', () => {
69  it('should convert a div to an HTMLElement', () => {
70    const divElement: Element = document.createElement('div');
71    expect(toHTMLElement(divElement)).toEqual(divElement);
72  });
73
74  it('should fail to convert an svg element to an HTMLElement', () => {
75    const svgElement = document.createElementNS(
76      'http://www.w3.org/2000/svg',
77      'svg',
78    );
79    expect(() => toHTMLElement(svgElement)).toThrow(Error);
80  });
81});
82
83describe('elementIsEditable', () => {
84  test('text input', () => {
85    const el = document.createElement('input');
86    el.setAttribute('type', 'text');
87    expect(elementIsEditable(el)).toBeTruthy();
88  });
89
90  test('radio input', () => {
91    const el = document.createElement('input');
92    el.setAttribute('type', 'radio');
93    expect(elementIsEditable(el)).toBeFalsy();
94  });
95
96  test('checkbox input', () => {
97    const el = document.createElement('input');
98    el.setAttribute('type', 'checkbox');
99    expect(elementIsEditable(el)).toBeFalsy();
100  });
101
102  test('button input', () => {
103    const el = document.createElement('input');
104    el.setAttribute('type', 'button');
105    expect(elementIsEditable(el)).toBeFalsy();
106  });
107
108  test('div', () => {
109    const el = document.createElement('div');
110    expect(elementIsEditable(el)).toBeFalsy();
111  });
112
113  test('textarea', () => {
114    const el = document.createElement('textarea');
115    expect(elementIsEditable(el)).toBeTruthy();
116  });
117
118  test('nested', () => {
119    const el = document.createElement('textarea');
120    const nested = document.createElement('div');
121    el.appendChild(nested);
122    expect(elementIsEditable(nested)).toBeTruthy();
123  });
124});
125
126describe('bindEventListener', () => {
127  let element: HTMLElement;
128  let handler: jest.Mock;
129
130  beforeEach(() => {
131    element = document.createElement('div');
132    handler = jest.fn();
133  });
134
135  test('adds the event listener and triggers the handler', () => {
136    const disposable = bindEventListener(element, 'click', handler);
137
138    // Simulate a click event
139    const event = new Event('click');
140    element.dispatchEvent(event);
141
142    // Ensure the handler was called
143    expect(handler).toHaveBeenCalledWith(event);
144
145    // Dispose of the event listener
146    disposable[Symbol.dispose]();
147
148    // Reset the mock and dispatch the event again
149    handler.mockReset();
150    element.dispatchEvent(event);
151
152    // Ensure the handler was not called after disposing
153    expect(handler).not.toHaveBeenCalled();
154  });
155
156  test('does not throw when disposing multiple times', () => {
157    const disposable = bindEventListener(element, 'click', handler);
158
159    expect(() => {
160      disposable[Symbol.dispose]();
161      disposable[Symbol.dispose]();
162    }).not.toThrow();
163  });
164});
165