@pie-lib/text-select 1.12.8 → 1.14.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/NEXT.CHANGELOG.json +1 -0
  3. package/lib/__tests__/text-select.test.js +56 -0
  4. package/lib/__tests__/utils.test.js +23 -0
  5. package/lib/index.js +9 -1
  6. package/lib/legend.js +1 -1
  7. package/lib/text-select.js +1 -1
  8. package/lib/token-select/__tests__/index.test.js +268 -0
  9. package/lib/token-select/__tests__/token.test.js +35 -0
  10. package/lib/token-select/index.js +4 -3
  11. package/lib/token-select/token.js +13 -20
  12. package/lib/tokenizer/__tests__/builder.test.js +399 -0
  13. package/lib/tokenizer/__tests__/controls.test.js +34 -0
  14. package/lib/tokenizer/__tests__/index.test.js +210 -0
  15. package/lib/tokenizer/__tests__/selection-utils.test.js +27 -0
  16. package/lib/tokenizer/__tests__/token-text.test.js +154 -0
  17. package/lib/tokenizer/builder.js +1 -1
  18. package/lib/tokenizer/controls.js +15 -1
  19. package/lib/tokenizer/index.js +1 -1
  20. package/lib/tokenizer/selection-utils.js +1 -1
  21. package/lib/tokenizer/token-text.js +12 -3
  22. package/lib/utils.js +1 -1
  23. package/package.json +7 -6
  24. package/src/__tests__/__snapshots__/text-select.test.jsx.snap +21 -0
  25. package/src/__tests__/text-select.test.jsx +34 -0
  26. package/src/__tests__/utils.test.jsx +27 -0
  27. package/src/index.js +2 -1
  28. package/src/token-select/__tests__/__snapshots__/index.test.jsx.snap +49 -0
  29. package/src/token-select/__tests__/__snapshots__/token.test.jsx.snap +31 -0
  30. package/src/token-select/__tests__/index.test.jsx +257 -0
  31. package/src/token-select/__tests__/token.test.jsx +33 -0
  32. package/src/token-select/index.jsx +3 -1
  33. package/src/token-select/token.jsx +11 -20
  34. package/src/tokenizer/__tests__/__snapshots__/controls.test.jsx.snap +59 -0
  35. package/src/tokenizer/__tests__/__snapshots__/index.test.jsx.snap +31 -0
  36. package/src/tokenizer/__tests__/__snapshots__/token-text.test.jsx.snap +17 -0
  37. package/src/tokenizer/__tests__/builder.test.js +256 -0
  38. package/src/tokenizer/__tests__/controls.test.jsx +25 -0
  39. package/src/tokenizer/__tests__/index.test.jsx +140 -0
  40. package/src/tokenizer/__tests__/selection-utils.test.js +26 -0
  41. package/src/tokenizer/__tests__/token-text.test.jsx +136 -0
  42. package/src/tokenizer/controls.jsx +20 -1
  43. package/src/tokenizer/token-text.jsx +9 -0
  44. package/README.md +0 -3
  45. package/lib/index.js.map +0 -1
  46. package/lib/legend.js.map +0 -1
  47. package/lib/text-select.js.map +0 -1
  48. package/lib/token-select/index.js.map +0 -1
  49. package/lib/token-select/token.js.map +0 -1
  50. package/lib/tokenizer/builder.js.map +0 -1
  51. package/lib/tokenizer/controls.js.map +0 -1
  52. package/lib/tokenizer/index.js.map +0 -1
  53. package/lib/tokenizer/selection-utils.js.map +0 -1
  54. package/lib/tokenizer/token-text.js.map +0 -1
  55. package/lib/utils.js.map +0 -1
@@ -0,0 +1,59 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`controls snapshot renders 1`] = `
4
+ <div>
5
+ <div>
6
+ <WithStyles(Button)
7
+ className="button"
8
+ color="primary"
9
+ disabled={false}
10
+ onClick={[MockFunction]}
11
+ size="small"
12
+ >
13
+ Words
14
+ </WithStyles(Button)>
15
+ <WithStyles(Button)
16
+ className="button"
17
+ color="primary"
18
+ disabled={false}
19
+ onClick={[MockFunction]}
20
+ size="small"
21
+ >
22
+ Sentences
23
+ </WithStyles(Button)>
24
+ <WithStyles(Button)
25
+ className="button"
26
+ color="primary"
27
+ disabled={false}
28
+ onClick={[MockFunction]}
29
+ size="small"
30
+ >
31
+ Paragraphs
32
+ </WithStyles(Button)>
33
+ <WithStyles(Button)
34
+ className="button"
35
+ color="secondary"
36
+ disabled={false}
37
+ onClick={[MockFunction]}
38
+ size="small"
39
+ >
40
+ Clear
41
+ </WithStyles(Button)>
42
+ </div>
43
+ <WithStyles(WithFormControlContext(FormControlLabel))
44
+ control={
45
+ <WithStyles(Switch)
46
+ checked={false}
47
+ classes={
48
+ Object {
49
+ "bar": "",
50
+ "checked": undefined,
51
+ }
52
+ }
53
+ onChange={[MockFunction]}
54
+ />
55
+ }
56
+ label="Set correct answers"
57
+ />
58
+ </div>
59
+ `;
@@ -0,0 +1,31 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`tokenizer snapshot renders 1`] = `
4
+ <div
5
+ className=""
6
+ >
7
+ <WithStyles(Controls)
8
+ onClear={[Function]}
9
+ onParagraphs={[Function]}
10
+ onSentences={[Function]}
11
+ onToggleCorrectMode={[Function]}
12
+ onWords={[Function]}
13
+ setCorrectMode={false}
14
+ />
15
+ <TokenText
16
+ className=""
17
+ onSelectToken={[Function]}
18
+ onTokenClick={[Function]}
19
+ text="foo"
20
+ tokens={
21
+ Array [
22
+ Object {
23
+ "end": 1,
24
+ "start": 0,
25
+ "text": "f",
26
+ },
27
+ ]
28
+ }
29
+ />
30
+ </div>
31
+ `;
@@ -0,0 +1,17 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`token-text snapshot renders 1`] = `
4
+ <div
5
+ onClick={[Function]}
6
+ >
7
+ <WithStyles(Component)
8
+ end={13}
9
+ key="0"
10
+ onClick={[Function]}
11
+ predefined={true}
12
+ start={0}
13
+ text="lorem
14
+ foo bar"
15
+ />
16
+ </div>
17
+ `;
@@ -0,0 +1,256 @@
1
+ import { normalize, sentences, words, paragraphs, sort, intersection } from '../builder';
2
+
3
+ const token = (start, end, text) => ({ start, end, text });
4
+
5
+ const selection = (start, end) => ({ start, end });
6
+
7
+ const o = (strings, ...exp) => {
8
+ return strings.reduce((acc, v, index) => {
9
+ const e = exp[index];
10
+ const s = typeof e === 'object' ? JSON.stringify(e) : e;
11
+ return `${acc}${v}${s || ''}`;
12
+ }, '');
13
+ };
14
+
15
+ describe('builder', () => {
16
+ describe('intersection', () => {
17
+ const assert = (selection, tokens, expected) => {
18
+ it(o`${selection}, ${tokens} => ${expected}`, () => {
19
+ const received = intersection(selection, tokens);
20
+ expect(received.results).toEqual(expected);
21
+ });
22
+ };
23
+
24
+ assert(selection(2, 3), [token(0, 1)], []);
25
+ assert(selection(1, 2), [token(0, 1)], []);
26
+ assert(selection(0, 1), [token(0, 1)], [{ token: token(0, 1), type: 'exact-fit' }]);
27
+ assert(selection(0, 2), [token(0, 1)], [{ token: token(0, 1), type: 'within-selection' }]);
28
+ assert(selection(0, 2), [token(1, 2)], [{ token: token(1, 2), type: 'within-selection' }]);
29
+ assert(
30
+ selection(0, 10),
31
+ [token(1, 2), token(2, 3)],
32
+ [
33
+ { token: token(1, 2), type: 'within-selection' },
34
+ { token: token(2, 3), type: 'within-selection' },
35
+ ],
36
+ );
37
+ assert(
38
+ selection(0, 10),
39
+ [token(1, 2), token(2, 11)],
40
+ [
41
+ { token: token(1, 2), type: 'within-selection' },
42
+ { token: token(2, 11), type: 'overlap' },
43
+ ],
44
+ );
45
+ });
46
+
47
+ describe('sort', () => {
48
+ it('sorts', () => {
49
+ const out = sort([token(1, 2), token(0, 1)]);
50
+ expect(out).toEqual([token(0, 1), token(1, 2)]);
51
+ });
52
+ it('sorts', () => {
53
+ const out = sort([token(0, 1), token(1, 2)]);
54
+ expect(out).toEqual([token(0, 1), token(1, 2)]);
55
+ });
56
+ xit('sorts', () => {
57
+ expect(() => sort([token(0, 2), token(1, 2)])).toThrow(Error);
58
+ });
59
+ });
60
+ describe('normalize', () => {
61
+ const assert = (input, tokens, expected) => {
62
+ it(`${input} + ${JSON.stringify(tokens)} -> ${JSON.stringify(expected)}`, () => {
63
+ const out = normalize(input, tokens);
64
+ expect(out).toEqual(expected);
65
+ });
66
+ };
67
+ assert(
68
+ null,
69
+ [],
70
+ [
71
+ {
72
+ text: '',
73
+ start: 0,
74
+ end: 0,
75
+ },
76
+ ],
77
+ );
78
+ assert(
79
+ 'abcde',
80
+ [
81
+ { text: 'b', start: 1, end: 2 },
82
+ { text: 'd', start: 3, end: 4 },
83
+ ],
84
+ [
85
+ { text: 'a', start: 0, end: 1 },
86
+ { text: 'b', start: 1, end: 2, predefined: true },
87
+ { text: 'c', start: 2, end: 3 },
88
+ { text: 'd', start: 3, end: 4, predefined: true },
89
+ { text: 'e', start: 4, end: 5 },
90
+ ],
91
+ );
92
+ assert(
93
+ 'abc',
94
+ [{ text: 'c', start: 2, end: 3 }],
95
+ [
96
+ { text: 'ab', start: 0, end: 2 },
97
+ { text: 'c', start: 2, end: 3, predefined: true },
98
+ ],
99
+ );
100
+
101
+ assert(
102
+ 'abc',
103
+ [
104
+ { text: 'c', start: 2, end: 3 },
105
+ { text: 'b', start: 1, end: 2 },
106
+ ],
107
+ [
108
+ { text: 'a', start: 0, end: 1 },
109
+ { text: 'b', start: 1, end: 2, predefined: true },
110
+ { text: 'c', start: 2, end: 3, predefined: true },
111
+ ],
112
+ );
113
+
114
+ assert(
115
+ 'abc',
116
+ [{ text: 'a', start: 0, end: 1 }],
117
+ [
118
+ { text: 'a', start: 0, end: 1, predefined: true },
119
+ { text: 'bc', start: 1, end: 3 },
120
+ ],
121
+ );
122
+
123
+ assert(
124
+ 'abcd',
125
+ [
126
+ { text: 'b', start: 1, end: 2 },
127
+ { text: 'c', start: 2, end: 3 },
128
+ { text: 'd', start: 3, end: 4 },
129
+ ],
130
+ [
131
+ { text: 'a', start: 0, end: 1 },
132
+ { text: 'b', start: 1, end: 2, predefined: true },
133
+ { text: 'c', start: 2, end: 3, predefined: true },
134
+ { text: 'd', start: 3, end: 4, predefined: true },
135
+ ],
136
+ );
137
+ assert(
138
+ 'abcde',
139
+ [
140
+ { text: 'b', start: 1, end: 2 },
141
+ { text: 'c', start: 2, end: 3 },
142
+ { text: 'd', start: 3, end: 4 },
143
+ ],
144
+ [
145
+ { text: 'a', start: 0, end: 1 },
146
+ { text: 'b', start: 1, end: 2, predefined: true },
147
+ { text: 'c', start: 2, end: 3, predefined: true },
148
+ { text: 'd', start: 3, end: 4, predefined: true },
149
+ { text: 'e', start: 4, end: 5 },
150
+ ],
151
+ );
152
+
153
+ // same token defined multiple times
154
+ assert(
155
+ 'abcde',
156
+ [
157
+ { text: 'c', start: 2, end: 3 },
158
+ { text: 'b', start: 1, end: 2 },
159
+ { text: 'c', start: 2, end: 3 },
160
+ { text: 'd', start: 3, end: 4 },
161
+ { text: 'c', start: 2, end: 3 },
162
+ ],
163
+ [
164
+ { text: 'a', start: 0, end: 1 },
165
+ { text: 'b', start: 1, end: 2, predefined: true },
166
+ { text: 'c', start: 2, end: 3, predefined: true },
167
+ { text: 'd', start: 3, end: 4, predefined: true },
168
+ { text: 'e', start: 4, end: 5 },
169
+ ],
170
+ );
171
+ });
172
+
173
+ describe('words', () => {
174
+ it('works', () => {
175
+ const out = words('foo. bar');
176
+ expect(out).toEqual([
177
+ {
178
+ text: 'foo.',
179
+ start: 0,
180
+ end: 4,
181
+ },
182
+ {
183
+ text: 'bar',
184
+ start: 5,
185
+ end: 8,
186
+ },
187
+ ]);
188
+ });
189
+ });
190
+
191
+ describe('sentences', () => {
192
+ it('foobar', () => {
193
+ const text = 'This is foo. This is bar.';
194
+ const out = sentences(text);
195
+ expect(out[0]).toEqual({ text: 'This is foo.', start: 0, end: 12 });
196
+ expect(out[1]).toEqual({ text: 'This is bar.', start: 13, end: 25 });
197
+ });
198
+
199
+ it('works', () => {
200
+ const text =
201
+ 'On Jan. 20, former Sen. Barack Obama became the 44th President of the USA. Millions attended the Inauguration.';
202
+
203
+ const out = sentences(text);
204
+ expect(out.length).toEqual(2);
205
+ });
206
+
207
+ it('works for sentences separated by \n', () => {
208
+ const text = 'This is foo\nThis is bar';
209
+ const out = sentences(text);
210
+ expect(out[0]).toEqual({ text: 'This is foo', start: 0, end: 11 });
211
+ expect(out[1]).toEqual({ text: 'This is bar', start: 12, end: 23 });
212
+ });
213
+
214
+ it('works for sentences ending in one-character-words', () => {
215
+ const text =
216
+ "This is Sentence 1. This is Sentence 2. This is Sentence 3. This is Sentence 4. Dr. A. said he'll call in 5.";
217
+
218
+ const out = sentences(text);
219
+
220
+ expect(out.length).toEqual(5);
221
+
222
+ expect(out).toEqual([
223
+ { text: 'This is Sentence 1.', start: 0, end: 19 },
224
+ { text: 'This is Sentence 2.', start: 20, end: 39 },
225
+ { text: 'This is Sentence 3.', start: 40, end: 59 },
226
+ { text: 'This is Sentence 4.', start: 60, end: 79 },
227
+ { text: "Dr. A. said he'll call in 5.", start: 80, end: 108 },
228
+ ]);
229
+ });
230
+ });
231
+
232
+ describe('paragraphs', () => {
233
+ it('foobar', () => {
234
+ const text = 'This is foo. This is bar.\nThis is foobar. This is barfoo.';
235
+ const out = paragraphs(text);
236
+ expect(out[0]).toEqual({
237
+ text: 'This is foo. This is bar.',
238
+ start: 0,
239
+ end: 25,
240
+ });
241
+ expect(out[1]).toEqual({
242
+ text: 'This is foobar. This is barfoo.',
243
+ start: 26,
244
+ end: 57,
245
+ });
246
+ });
247
+ it('works', () => {
248
+ const text =
249
+ 'On Jan. 20, former Sen. Barack Obama became the 44th President of the USA. Millions attended the Inauguration.' +
250
+ '\\ndadadadadadadadada.';
251
+
252
+ const out = paragraphs(text);
253
+ expect(out.length).toEqual(1);
254
+ });
255
+ });
256
+ });
@@ -0,0 +1,25 @@
1
+ import { Controls } from '../controls';
2
+ import React from 'react';
3
+ import { shallow, configure } from 'enzyme';
4
+ import Adapter from 'enzyme-adapter-react-16';
5
+
6
+ configure({ adapter: new Adapter() });
7
+
8
+ describe('controls', () => {
9
+ describe('snapshot', () => {
10
+ it('renders', () => {
11
+ const w = shallow(
12
+ <Controls
13
+ classes={{ button: 'button' }}
14
+ onClear={jest.fn()}
15
+ onWords={jest.fn()}
16
+ onSentences={jest.fn()}
17
+ onParagraphs={jest.fn()}
18
+ setCorrectMode={false}
19
+ onToggleCorrectMode={jest.fn()}
20
+ />,
21
+ );
22
+ expect(w).toMatchSnapshot();
23
+ });
24
+ });
25
+ });
@@ -0,0 +1,140 @@
1
+ import { Tokenizer } from '../index';
2
+ import React from 'react';
3
+ import { shallow } from 'enzyme';
4
+ import { words, sentences, paragraphs } from '../builder';
5
+
6
+ const tokens = () => [
7
+ {
8
+ start: 0,
9
+ end: 1,
10
+ text: 'f',
11
+ },
12
+ ];
13
+
14
+ const eff = () => tokens()[0];
15
+
16
+ jest.mock('../builder', () => ({
17
+ words: jest.fn().mockReturnValue([{ start: 0, end: 3, text: 'foo' }]),
18
+ sentences: jest.fn().mockReturnValue([{ start: 0, end: 3, text: 'foo' }]),
19
+ paragraphs: jest.fn().mockReturnValue([{ start: 0, end: 3, text: 'foo' }]),
20
+ }));
21
+ describe('tokenizer', () => {
22
+ describe('snapshot', () => {
23
+ it('renders', () => {
24
+ const w = shallow(<Tokenizer text="foo" classes={{}} onChange={jest.fn()} tokens={tokens()} />);
25
+ expect(w).toMatchSnapshot();
26
+ });
27
+ });
28
+
29
+ describe('logic', () => {
30
+ let w;
31
+ let onChange;
32
+
33
+ beforeEach(() => {
34
+ onChange = jest.fn();
35
+ w = shallow(<Tokenizer text="foo" classes={{}} onChange={onChange} tokens={tokens()} />);
36
+ });
37
+ describe('tokenIndex', () => {
38
+ it('returns 0', () => {
39
+ const index = w.instance().tokenIndex(eff());
40
+ expect(index).toEqual(0);
41
+ });
42
+
43
+ it('returns -1', () => {
44
+ const index = w.instance().tokenIndex({ start: 2, end: 3, text: 'f' });
45
+ expect(index).toEqual(-1);
46
+ });
47
+ });
48
+
49
+ describe('tokenClick', () => {
50
+ let i;
51
+
52
+ beforeEach(() => {
53
+ i = w.instance();
54
+ i.setCorrect = jest.fn();
55
+ i.removeToken = jest.fn();
56
+ });
57
+
58
+ it('calls removeToken if setCorrectMode == false', () => {
59
+ i.tokenClick(eff());
60
+ expect(i.setCorrect).not.toBeCalled();
61
+ expect(i.removeToken).toBeCalled();
62
+ });
63
+
64
+ it('calls setCorrect if setCorrectMode == true', () => {
65
+ i.setState({ setCorrectMode: true });
66
+ i.tokenClick(eff());
67
+ expect(i.setCorrect).toBeCalled();
68
+ expect(i.removeToken).not.toBeCalled();
69
+ });
70
+ });
71
+
72
+ describe('selectToken', () => {
73
+ it('calls onChange', () => {
74
+ w.instance().selectToken({ start: 1, end: 3, text: 'oo' }, [{ start: 0, end: 1, text: 'f' }]);
75
+ expect(onChange).toBeCalledWith([{ start: 1, end: 3, text: 'oo' }], '');
76
+ });
77
+ });
78
+
79
+ describe('buildParagraphsTokens', () => {
80
+ it('calls paragraphs', () => {
81
+ w.instance().buildTokens('paragraph', paragraphs);
82
+ expect(paragraphs).toBeCalledWith('foo');
83
+ });
84
+ });
85
+
86
+ describe('buildSentenceTokens', () => {
87
+ it('calls sentences', () => {
88
+ w.instance().buildTokens('sentence', sentences);
89
+ expect(sentences).toBeCalledWith('foo');
90
+ });
91
+ });
92
+
93
+ describe('buildWordTokens', () => {
94
+ it('calls words', () => {
95
+ w.instance().buildTokens('word', words);
96
+ expect(words).toBeCalledWith('foo');
97
+ });
98
+ });
99
+
100
+ describe('clear', () => {
101
+ it('calls onChange with an empty array', () => {
102
+ w.instance().clear();
103
+ expect(onChange).toBeCalledWith([], '');
104
+ });
105
+ });
106
+
107
+ describe('toggleCorrectMode', () => {
108
+ it('set state', () => {
109
+ w.setState({ setCorrectMode: true });
110
+ w.instance().toggleCorrectMode();
111
+ expect(w.state('setCorrectMode')).toEqual(false);
112
+ });
113
+ });
114
+
115
+ describe('setCorrect', () => {
116
+ it('calls onChange', () => {
117
+ w.instance().setCorrect({ start: 0, end: 1, text: 'f' });
118
+ expect(onChange).toBeCalledWith([{ start: 0, end: 1, text: 'f', correct: true }], '');
119
+ });
120
+ it('calls onChange w/ correct: false', () => {
121
+ w.setProps({
122
+ tokens: [{ start: 0, end: 1, text: 'f', correct: true }],
123
+ });
124
+ w.instance().setCorrect({ start: 0, end: 1, text: 'f' });
125
+ expect(onChange).toBeCalledWith([{ start: 0, end: 1, text: 'f', correct: false }], '');
126
+ });
127
+ });
128
+
129
+ describe('removeToken', () => {
130
+ it('calls onChange', () => {
131
+ w.instance().removeToken({ start: 0, end: 1, text: 'f' });
132
+ expect(onChange).toBeCalledWith([], '');
133
+ });
134
+ it('does not call onChange if it cant find the token', () => {
135
+ w.instance().removeToken({ start: 2, end: 3, text: 'a' });
136
+ expect(onChange).not.toBeCalled();
137
+ });
138
+ });
139
+ });
140
+ });
@@ -0,0 +1,26 @@
1
+ import { clearSelection, getCaretCharacterOffsetWithin } from '../selection-utils';
2
+
3
+ describe('selection-utils', () => {
4
+ let selection;
5
+ let range;
6
+ beforeEach(() => {
7
+ selection = {
8
+ removeAllRanges: jest.fn(),
9
+ addRange: jest.fn(),
10
+ getRangeAt: jest.fn().mockReturnValue(range),
11
+ };
12
+ global.document.getSelection = jest.fn().mockReturnValue(selection);
13
+ global.document.createRange = jest.fn();
14
+ });
15
+
16
+ describe('clearSelection', () => {
17
+ it('calls removeAllRanges', () => {
18
+ clearSelection();
19
+ expect(selection.removeAllRanges).toBeCalled();
20
+ });
21
+ });
22
+
23
+ xdescribe('getCaretCharacterOffsetWithin', () => {
24
+ it('TODO', () => {});
25
+ });
26
+ });
@@ -0,0 +1,136 @@
1
+ import { shallow } from 'enzyme';
2
+ import React from 'react';
3
+ import TokenText from '../token-text';
4
+ import { intersection } from '../builder';
5
+ import { clearSelection, getCaretCharacterOffsetWithin } from '../selection-utils';
6
+
7
+ jest.mock('../selection-utils', () => ({
8
+ clearSelection: jest.fn(),
9
+ getCaretCharacterOffsetWithin: jest.fn().mockReturnValue(10),
10
+ }));
11
+
12
+ jest.mock('../builder', () => ({
13
+ intersection: jest.fn().mockReturnValue({
14
+ hasOverlap: jest.fn().mockReturnValue(false),
15
+ surroundedTokens: jest.fn().mockReturnValue([]),
16
+ }),
17
+ normalize: jest.fn().mockReturnValue([
18
+ {
19
+ text: `lorem\nfoo bar`,
20
+ start: 0,
21
+ end: 13,
22
+ predefined: true,
23
+ },
24
+ ]),
25
+ }));
26
+
27
+ const tokens = () => [
28
+ {
29
+ start: 0,
30
+ end: 7,
31
+ text: `lorem\nfoo bar`,
32
+ },
33
+ ];
34
+
35
+ const mkEvent = () => ({
36
+ preventDefault: jest.fn(),
37
+ });
38
+
39
+ describe('token-text', () => {
40
+ describe('snapshot', () => {
41
+ it('renders', () => {
42
+ const w = shallow(
43
+ <TokenText onTokenClick={jest.fn()} onSelectToken={jest.fn()} text={`lorem\nfoo bar`} tokens={tokens()} />,
44
+ );
45
+ expect(w).toMatchSnapshot();
46
+ });
47
+ });
48
+
49
+ describe('logic', () => {
50
+ let w;
51
+ let onSelectToken;
52
+ let onTokenClick;
53
+ beforeEach(() => {
54
+ global.window.getSelection = jest.fn().mockReturnValue({
55
+ toString: () => 'bar',
56
+ });
57
+
58
+ onSelectToken = jest.fn();
59
+ onTokenClick = jest.fn();
60
+
61
+ w = shallow(
62
+ <TokenText
63
+ onTokenClick={onTokenClick}
64
+ onSelectToken={onSelectToken}
65
+ text={`lorem\nfoo bar`}
66
+ tokens={tokens()}
67
+ />,
68
+ );
69
+ });
70
+
71
+ describe('mouseup', () => {
72
+ it('calls event.preventDefault', () => {
73
+ const event = mkEvent();
74
+ w.instance().onClick(event);
75
+ expect(event.preventDefault).toBeCalled();
76
+ });
77
+
78
+ it('calls getCaretCharacterOffsetWithin', () => {
79
+ const event = mkEvent();
80
+ w.instance().root = {};
81
+ w.instance().onClick(event);
82
+ expect(getCaretCharacterOffsetWithin).toBeCalledWith({});
83
+ });
84
+
85
+ it('calls clear selection if there is an overlap', () => {
86
+ intersection.mockReturnValue({
87
+ hasOverlap: true,
88
+ });
89
+ const event = mkEvent();
90
+ w.instance().root = {};
91
+ w.instance().onClick(event);
92
+ expect(clearSelection).toBeCalled();
93
+ expect(onSelectToken).not.toBeCalled();
94
+ });
95
+
96
+ it('calls onSelectToken', () => {
97
+ const event = mkEvent();
98
+ intersection.mockReturnValue({
99
+ hasOverlap: false,
100
+ surroundedTokens: [],
101
+ });
102
+ w.instance().root = {};
103
+ w.instance().onClick(event);
104
+ expect(onSelectToken).toBeCalledWith({ text: 'bar', start: 10, end: 13 }, []);
105
+ });
106
+
107
+ it('does not call onSelectToken for ["\n", " ", "\t"]', () => {
108
+ const event = mkEvent();
109
+
110
+ intersection.mockReturnValue({
111
+ hasOverlap: false,
112
+ surroundedTokens: [],
113
+ });
114
+ w.instance().root = {};
115
+
116
+ global.window.getSelection = jest.fn().mockReturnValue({
117
+ toString: () => '\n',
118
+ });
119
+ w.instance().onClick(event);
120
+ expect(onSelectToken).not.toBeCalled();
121
+
122
+ global.window.getSelection = jest.fn().mockReturnValue({
123
+ toString: () => ' ',
124
+ });
125
+ w.instance().onClick(event);
126
+ expect(onSelectToken).not.toBeCalled();
127
+
128
+ global.window.getSelection = jest.fn().mockReturnValue({
129
+ toString: () => '\t',
130
+ });
131
+ w.instance().onClick(event);
132
+ expect(onSelectToken).not.toBeCalled();
133
+ });
134
+ });
135
+ });
136
+ });